aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-02-04 10:57:43 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2018-02-04 10:57:43 -0800
commit4141cf676b9e345d3ddeb1710dd3156a09c50244 (patch)
tree4b2b6249e99efdd47eafa5780f106d593f64708b
parent3462ac57033e79a87dbae2497773f22b9c536fbc (diff)
parente38c85644e11c6dc5a39305c96b617f63403423d (diff)
Merge branch 'i2c/for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "I2C has the following changes for you: - new flag to mark DMA safe buffers in i2c_msg. Also, some infrastructure around it. And docs. - huge refactoring of the at24 driver led by the new maintainer Bartosz - update I2C bus recovery to send STOP after recovery - conversion from gpio to gpiod for I2C bus recovery - adding a fault-injector to the i2c-gpio driver - lots of small driver improvements, and bigger ones to i2c-sh_mobile" * 'i2c/for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (99 commits) i2c: mv64xxx: Add myself as maintainer for this driver i2c: mv64xxx: Fix clock resource by adding an optional bus clock i2c: mv64xxx: Remove useless test before clk_disable_unprepare i2c: mxs: use true and false for boolean values i2c: meson: update doc description to fix build warnings i2c: meson: add configurable divider factors dt-bindings: i2c: update documentation for the Meson-AXG i2c: imx-lpi2c: add runtime pm support i2c: rcar: fix some trivial typos in comments i2c: davinci: fix the cpufreq transition i2c: rk3x: add proper kerneldoc header i2c: rk3x: account for const type of of_device_id.data i2c: acorn: remove outdated path from file header i2c: acorn: add MODULE_LICENSE tag i2c: rcar: implement bus recovery i2c: send STOP after successful bus recovery i2c: ensure SDA is released in recovery if SDA is controllable i2c: add 'set_sda' to bus_recovery_info i2c: add identifier in declarations for i2c_bus_recovery i2c: make kerneldoc about bus recovery more precise ...
-rw-r--r--Documentation/devicetree/bindings/eeprom/at24.txt78
-rw-r--r--Documentation/devicetree/bindings/eeprom/eeprom.txt47
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-meson.txt6
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mtk.txt1
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt13
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt20
-rw-r--r--Documentation/i2c/DMA-considerations67
-rw-r--r--Documentation/i2c/gpio-fault-injection54
-rw-r--r--MAINTAINERS8
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c15
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c15
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c5
-rw-r--r--drivers/i2c/busses/Kconfig8
-rw-r--r--drivers/i2c/busses/i2c-acorn.c8
-rw-r--r--drivers/i2c/busses/i2c-davinci.c37
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c20
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h2
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c57
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c29
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c64
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c2
-rw-r--r--drivers/i2c/busses/i2c-gpio.c122
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c68
-rw-r--r--drivers/i2c/busses/i2c-imx.c20
-rw-r--r--drivers/i2c/busses/i2c-ismt.c42
-rw-r--r--drivers/i2c/busses/i2c-meson.c34
-rw-r--r--drivers/i2c/busses/i2c-mpc.c57
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c40
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c20
-rw-r--r--drivers/i2c/busses/i2c-mxs.c4
-rw-r--r--drivers/i2c/busses/i2c-rcar.c62
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c17
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c191
-rw-r--r--drivers/i2c/i2c-core-base.c212
-rw-r--r--drivers/i2c/i2c-core-smbus.c45
-rw-r--r--drivers/i2c/i2c-dev.c2
-rw-r--r--drivers/i2c/muxes/Kconfig6
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c38
-rw-r--r--drivers/i2c/muxes/i2c-mux-reg.c3
-rw-r--r--drivers/misc/eeprom/Kconfig1
-rw-r--r--drivers/misc/eeprom/at24.c731
-rw-r--r--include/linux/i2c.h112
-rw-r--r--include/linux/platform_data/at24.h2
-rw-r--r--include/linux/platform_data/i2c-davinci.h5
-rw-r--r--include/uapi/linux/i2c.h3
45 files changed, 1381 insertions, 1012 deletions
diff --git a/Documentation/devicetree/bindings/eeprom/at24.txt b/Documentation/devicetree/bindings/eeprom/at24.txt
new file mode 100644
index 000000000000..1812c848e369
--- /dev/null
+++ b/Documentation/devicetree/bindings/eeprom/at24.txt
@@ -0,0 +1,78 @@
+EEPROMs (I2C)
+
+Required properties:
+
+ - compatible: Must be a "<manufacturer>,<model>" pair. The following <model>
+ values are supported (assuming "atmel" as manufacturer):
+
+ "atmel,24c00",
+ "atmel,24c01",
+ "atmel,24cs01",
+ "atmel,24c02",
+ "atmel,24cs02",
+ "atmel,24mac402",
+ "atmel,24mac602",
+ "atmel,spd",
+ "atmel,24c04",
+ "atmel,24cs04",
+ "atmel,24c08",
+ "atmel,24cs08",
+ "atmel,24c16",
+ "atmel,24cs16",
+ "atmel,24c32",
+ "atmel,24cs32",
+ "atmel,24c64",
+ "atmel,24cs64",
+ "atmel,24c128",
+ "atmel,24c256",
+ "atmel,24c512",
+ "atmel,24c1024",
+
+ If <manufacturer> is not "atmel", then a fallback must be used
+ with the same <model> and "atmel" as manufacturer.
+
+ Example:
+ compatible = "microchip,24c128", "atmel,24c128";
+
+ Supported manufacturers are:
+
+ "catalyst",
+ "microchip",
+ "ramtron",
+ "renesas",
+ "nxp",
+ "st",
+
+ Some vendors use different model names for chips which are just
+ variants of the above. Known such exceptions are listed below:
+
+ "renesas,r1ex24002" - the fallback is "atmel,24c02"
+
+ - reg: The I2C address of the EEPROM.
+
+Optional properties:
+
+ - pagesize: The length of the pagesize for writing. Please consult the
+ manual of your device, that value varies a lot. A wrong value
+ may result in data loss! If not specified, a safety value of
+ '1' is used which will be very slow.
+
+ - read-only: This parameterless property disables writes to the eeprom.
+
+ - size: Total eeprom size in bytes.
+
+ - no-read-rollover: This parameterless property indicates that the
+ multi-address eeprom does not automatically roll over
+ reads to the next slave address. Please consult the
+ manual of your device.
+
+ - wp-gpios: GPIO to which the write-protect pin of the chip is connected.
+
+Example:
+
+eeprom@52 {
+ compatible = "atmel,24c32";
+ reg = <0x52>;
+ pagesize = <32>;
+ wp-gpios = <&gpio1 3 0>;
+};
diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
deleted file mode 100644
index 27f2bc15298a..000000000000
--- a/Documentation/devicetree/bindings/eeprom/eeprom.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-EEPROMs (I2C)
-
-Required properties:
-
- - compatible : should be "<manufacturer>,<type>", like these:
-
- "atmel,24c00", "atmel,24c01", "atmel,24c02", "atmel,24c04",
- "atmel,24c08", "atmel,24c16", "atmel,24c32", "atmel,24c64",
- "atmel,24c128", "atmel,24c256", "atmel,24c512", "atmel,24c1024"
-
- "catalyst,24c32"
-
- "microchip,24c128"
-
- "ramtron,24c64"
-
- "renesas,r1ex24002"
-
- The following manufacturers values have been deprecated:
- "at", "at24"
-
- If there is no specific driver for <manufacturer>, a generic
- device with <type> and manufacturer "atmel" should be used.
- Possible types are:
- "24c00", "24c01", "24c02", "24c04", "24c08", "24c16", "24c32", "24c64",
- "24c128", "24c256", "24c512", "24c1024", "spd"
-
- - reg : the I2C address of the EEPROM
-
-Optional properties:
-
- - pagesize : the length of the pagesize for writing. Please consult the
- manual of your device, that value varies a lot. A wrong value
- may result in data loss! If not specified, a safety value of
- '1' is used which will be very slow.
-
- - read-only: this parameterless property disables writes to the eeprom
-
- - size: total eeprom size in bytes
-
-Example:
-
-eeprom@52 {
- compatible = "atmel,24c32";
- reg = <0x52>;
- pagesize = <32>;
-};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-meson.txt b/Documentation/devicetree/bindings/i2c/i2c-meson.txt
index 611b934c7e10..13d410de077c 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-meson.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-meson.txt
@@ -1,7 +1,11 @@
Amlogic Meson I2C controller
Required properties:
- - compatible: must be "amlogic,meson6-i2c" or "amlogic,meson-gxbb-i2c"
+ - compatible: must be:
+ "amlogic,meson6-i2c" for Meson8 and compatible SoCs
+ "amlogic,meson-gxbb-i2c" for GXBB and compatible SoCs
+ "amlogic,meson-axg-i2c"for AXG and compatible SoCs
+
- reg: physical address and length of the device registers
- interrupts: a single interrupt specifier
- clocks: clock for the device
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
index ff7bf37deb43..e199695b1c96 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt
@@ -5,6 +5,7 @@ The MediaTek's I2C controller is used to interface with I2C devices.
Required properties:
- compatible: value should be either of the following.
"mediatek,mt2701-i2c", "mediatek,mt6577-i2c": for MediaTek MT2701
+ "mediatek,mt2712-i2c": for MediaTek MT2712
"mediatek,mt6577-i2c": for MediaTek MT6577
"mediatek,mt6589-i2c": for MediaTek MT6589
"mediatek,mt7622-i2c": for MediaTek MT7622
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
index aa097045a10e..34d91501342e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt
@@ -1,10 +1,19 @@
* NXP PCA954x I2C bus switch
+The driver supports NXP PCA954x and PCA984x I2C mux/switch devices.
+
Required Properties:
- compatible: Must contain one of the following.
- "nxp,pca9540", "nxp,pca9542", "nxp,pca9543", "nxp,pca9544",
- "nxp,pca9545", "nxp,pca9546", "nxp,pca9547", "nxp,pca9548"
+ "nxp,pca9540",
+ "nxp,pca9542",
+ "nxp,pca9543",
+ "nxp,pca9544",
+ "nxp,pca9545",
+ "nxp,pca9546", "nxp,pca9846",
+ "nxp,pca9547", "nxp,pca9847",
+ "nxp,pca9548", "nxp,pca9848",
+ "nxp,pca9849"
- reg: The I2C address of the device.
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
index 5c30026921ae..0ffe65a316ae 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
@@ -25,6 +25,15 @@ default frequency is 100kHz
whenever you're using the "allwinner,sun6i-a31-i2c"
compatible.
+ - clocks: : pointers to the reference clocks for this device, the
+ first one is the one used for the clock on the i2c bus,
+ the second one is the clock used to acces the registers
+ of the controller
+
+ - clock-names : names of used clocks, mandatory if the second clock is
+ used, the name must be "core", and "reg" (the latter is
+ only for Armada 7K/8K).
+
Examples:
i2c@11000 {
@@ -42,3 +51,14 @@ For the Armada XP:
interrupts = <29>;
clock-frequency = <100000>;
};
+
+For the Armada 7040:
+
+ i2c@701000 {
+ compatible = "marvell,mv78230-i2c";
+ reg = <0x701000 0x20>;
+ interrupts = <29>;
+ clock-frequency = <100000>;
+ clock-names = "core", "reg";
+ clocks = <&core_clock>, <&reg_clock>;
+ };
diff --git a/Documentation/i2c/DMA-considerations b/Documentation/i2c/DMA-considerations
new file mode 100644
index 000000000000..966610aa4620
--- /dev/null
+++ b/Documentation/i2c/DMA-considerations
@@ -0,0 +1,67 @@
+=================
+Linux I2C and DMA
+=================
+
+Given that i2c is a low-speed bus, over which the majority of messages
+transferred are small, it is not considered a prime user of DMA access. At this
+time of writing, only 10% of I2C bus master drivers have DMA support
+implemented. And the vast majority of transactions are so small that setting up
+DMA for it will likely add more overhead than a plain PIO transfer.
+
+Therefore, it is *not* mandatory that the buffer of an I2C message is DMA safe.
+It does not seem reasonable to apply additional burdens when the feature is so
+rarely used. However, it is recommended to use a DMA-safe buffer if your
+message size is likely applicable for DMA. Most drivers have this threshold
+around 8 bytes (as of today, this is mostly an educated guess, however). For
+any message of 16 byte or larger, it is probably a really good idea. Please
+note that other subsystems you use might add requirements. E.g., if your
+I2C bus master driver is using USB as a bridge, then you need to have DMA
+safe buffers always, because USB requires it.
+
+Clients
+-------
+
+For clients, if you use a DMA safe buffer in i2c_msg, set the I2C_M_DMA_SAFE
+flag with it. Then, the I2C core and drivers know they can safely operate DMA
+on it. Note that using this flag is optional. I2C host drivers which are not
+updated to use this flag will work like before. And like before, they risk
+using an unsafe DMA buffer. To improve this situation, using I2C_M_DMA_SAFE in
+more and more clients and host drivers is the planned way forward. Note also
+that setting this flag makes only sense in kernel space. User space data is
+copied into kernel space anyhow. The I2C core makes sure the destination
+buffers in kernel space are always DMA capable. Also, when the core emulates
+SMBus transactions via I2C, the buffers for block transfers are DMA safe. Users
+of i2c_master_send() and i2c_master_recv() functions can now use DMA safe
+variants (i2c_master_send_dmasafe() and i2c_master_recv_dmasafe()) once they
+know their buffers are DMA safe. Users of i2c_transfer() must set the
+I2C_M_DMA_SAFE flag manually.
+
+Masters
+-------
+
+Bus master drivers wishing to implement safe DMA can use helper functions from
+the I2C core. One gives you a DMA-safe buffer for a given i2c_msg as long as a
+certain threshold is met::
+
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, threshold_in_byte);
+
+If a buffer is returned, it is either msg->buf for the I2C_M_DMA_SAFE case or a
+bounce buffer. But you don't need to care about that detail, just use the
+returned buffer. If NULL is returned, the threshold was not met or a bounce
+buffer could not be allocated. Fall back to PIO in that case.
+
+In any case, a buffer obtained from above needs to be released. It ensures data
+is copied back to the message and a potentially used bounce buffer is freed::
+
+ i2c_release_dma_safe_msg_buf(msg, dma_buf);
+
+The bounce buffer handling from the core is generic and simple. It will always
+allocate a new bounce buffer. If you want a more sophisticated handling (e.g.
+reusing pre-allocated buffers), you are free to implement your own.
+
+Please also check the in-kernel documentation for details. The i2c-sh_mobile
+driver can be used as a reference example how to use the above helpers.
+
+Final note: If you plan to use DMA with I2C (or with anything else, actually)
+make sure you have CONFIG_DMA_API_DEBUG enabled during development. It can help
+you find various issues which can be complex to debug otherwise.
diff --git a/Documentation/i2c/gpio-fault-injection b/Documentation/i2c/gpio-fault-injection
new file mode 100644
index 000000000000..e0c4f775e239
--- /dev/null
+++ b/Documentation/i2c/gpio-fault-injection
@@ -0,0 +1,54 @@
+Linux I2C fault injection
+=========================
+
+The GPIO based I2C bus master driver can be configured to provide fault
+injection capabilities. It is then meant to be connected to another I2C bus
+which is driven by the I2C bus master driver under test. The GPIO fault
+injection driver can create special states on the bus which the other I2C bus
+master driver should handle gracefully.
+
+Once the Kconfig option I2C_GPIO_FAULT_INJECTOR is enabled, there will be an
+'i2c-fault-injector' subdirectory in the Kernel debugfs filesystem, usually
+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.
+
+"scl"
+-----
+
+By reading this file, you get the current state of SCL. By writing, you can
+change its state to either force it low or to release it again. So, by using
+"echo 0 > scl" you force SCL low and thus, no communication will be possible
+because the bus master under test will not be able to clock. It should detect
+the condition of SCL being unresponsive and report an error to the upper
+layers.
+
+"sda"
+-----
+
+By reading this file, you get the current state of SDA. By writing, you can
+change its state to either force it low or to release it again. So, by using
+"echo 0 > sda" you force SDA low and thus, data cannot be transmitted. The bus
+master under test should detect this condition and trigger a bus recovery (see
+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
+'incomplete_transfer' file.
+
+"incomplete_transfer"
+---------------------
+
+This file is write only and you need to write the address of an existing I2C
+client device to it. Then, a transfer to this device will be started, but it
+will stop at the ACK phase after the address of the client has been
+transmitted. Because the device will ACK its presence, this results in SDA
+being pulled low by the device while SCL is high. So, similar to the "sda" file
+above, the bus master under test should detect this condition and try a bus
+recovery. This time, however, it should succeed and the device should release
+SDA after toggling SCL. Please note: there are I2C client devices which detect
+a stuck SDA on their side and release it on their own after a few milliseconds.
+Also, there are external devices deglitching and monitoring the I2C bus. They
+can also detect a stuck SDA and will init a bus recovery on their own. If you
+want to implement bus recovery in a bus master driver, make sure you checked
+your hardware setup carefully before.
diff --git a/MAINTAINERS b/MAINTAINERS
index f3bac2a8c6d6..e15f4e201471 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2288,7 +2288,9 @@ F: include/linux/async_tx.h
AT24 EEPROM DRIVER
M: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-i2c@vger.kernel.org
+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
@@ -6580,6 +6582,12 @@ F: drivers/i2c/i2c-mux.c
F: drivers/i2c/muxes/
F: include/linux/i2c-mux.h
+I2C MV64XXX MARVELL AND ALLWINNER DRIVER
+M: Gregory CLEMENT <gregory.clement@free-electrons.com>
+L: linux-i2c@vger.kernel.org
+S: Maintained
+F: drivers/i2c/busses/i2c-mv64xxx.c
+
I2C OVER PARALLEL PORT
M: Jean Delvare <jdelvare@suse.com>
L: linux-i2c@vger.kernel.org
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 62e7bc3018f0..e457f299cd44 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -17,6 +17,7 @@
#include <linux/mtd/rawnand.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
#include <media/i2c/tvp514x.h>
@@ -108,11 +109,20 @@ static struct platform_device davinci_nand_device = {
},
};
+static struct gpiod_lookup_table i2c_recovery_gpiod_table = {
+ .dev_id = "i2c_davinci",
+ .table = {
+ GPIO_LOOKUP("davinci_gpio", 15, "sda",
+ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+ GPIO_LOOKUP("davinci_gpio", 14, "scl",
+ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+ },
+};
+
static struct davinci_i2c_platform_data i2c_pdata = {
.bus_freq = 400 /* kHz */,
.bus_delay = 0 /* usec */,
- .sda_pin = 15,
- .scl_pin = 14,
+ .gpio_recovery = true,
};
static int dm355evm_mmc_gpios = -EINVAL;
@@ -141,6 +151,7 @@ static struct i2c_board_info dm355evm_i2c_info[] = {
static void __init evm_init_i2c(void)
{
+ gpiod_add_lookup_table(&i2c_recovery_gpiod_table);
davinci_init_i2c(&i2c_pdata);
gpio_request(5, "dm355evm_msp");
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index b07c9b18d427..85e6fb33b1ee 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/i2c.h>
#include <linux/platform_data/pcf857x.h>
#include <linux/platform_data/at24.h>
@@ -595,18 +596,28 @@ static struct i2c_board_info __initdata i2c_info[] = {
},
};
+static struct gpiod_lookup_table i2c_recovery_gpiod_table = {
+ .dev_id = "i2c_davinci",
+ .table = {
+ GPIO_LOOKUP("davinci_gpio", 44, "sda",
+ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+ GPIO_LOOKUP("davinci_gpio", 43, "scl",
+ GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
+ },
+};
+
/* The msp430 uses a slow bitbanged I2C implementation (ergo 20 KHz),
* which requires 100 usec of idle bus after i2c writes sent to it.
*/
static struct davinci_i2c_platform_data i2c_pdata = {
.bus_freq = 20 /* kHz */,
.bus_delay = 100 /* usec */,
- .sda_pin = 44,
- .scl_pin = 43,
+ .gpio_recovery = true,
};
static void __init evm_init_i2c(void)
{
+ gpiod_add_lookup_table(&i2c_recovery_gpiod_table);
davinci_init_i2c(&i2c_pdata);
i2c_add_driver(&dm6446evm_msp_driver);
i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 1147bddb8b2c..3df0efd69ae3 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -649,6 +649,11 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (bit_adap->getscl == NULL)
adap->quirks = &i2c_bit_quirk_no_clk_stretch;
+ /* Bring bus to a known state. Looks like STOP if bus is not free yet */
+ setscl(bit_adap, 1);
+ udelay(bit_adap->udelay);
+ setsda(bit_adap, 1);
+
ret = add_adapter(adap);
if (ret < 0)
return ret;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 009345d8f49d..a9805c7cb305 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -603,6 +603,14 @@ config I2C_GPIO
This is a very simple bitbanging I2C driver utilizing the
arch-neutral GPIO API to control the SCL and SDA lines.
+config I2C_GPIO_FAULT_INJECTOR
+ bool "GPIO-based fault injector"
+ depends on I2C_GPIO
+ help
+ This adds some functionality to the i2c-gpio driver which can inject
+ faults to an I2C bus, so another bus master can be stress-tested.
+ This is for debugging. If unsure, say 'no'.
+
config I2C_HIGHLANDER
tristate "Highlander FPGA SMBus interface"
depends on SH_HIGHLANDER
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index 9d7be5af2bf2..f4a5ae69bf6a 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/acorn/char/i2c.c
+ * ARM IOC/IOMD i2c driver.
*
* Copyright (C) 2000 Russell King
*
@@ -7,8 +7,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * ARM IOC/IOMD i2c driver.
- *
* On Acorn machines, the following i2c devices are on the bus:
* - PCF8583 real time clock & static RAM
*/
@@ -94,3 +92,7 @@ static int __init i2c_ioc_init(void)
}
module_init(i2c_ioc_init);
+
+MODULE_AUTHOR("Russell King <linux@armlinux.org.uk>");
+MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 2ead9b9eebb7..75d6ab177055 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -33,7 +33,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
#include <linux/platform_data/i2c-davinci.h>
#include <linux/pm_runtime.h>
@@ -139,7 +139,6 @@ struct davinci_i2c_dev {
u8 terminate;
struct i2c_adapter adapter;
#ifdef CONFIG_CPU_FREQ
- struct completion xfr_complete;
struct notifier_block freq_transition;
#endif
struct davinci_i2c_platform_data *pdata;
@@ -294,7 +293,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
}
/*
- * This routine does i2c bus recovery by using i2c_generic_gpio_recovery
+ * This routine does i2c bus recovery by using i2c_generic_scl_recovery
* which is provided by I2C Bus recovery infrastructure.
*/
static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap)
@@ -316,7 +315,7 @@ static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap)
}
static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = {
- .recover_bus = i2c_generic_gpio_recovery,
+ .recover_bus = i2c_generic_scl_recovery,
.prepare_recovery = davinci_i2c_prepare_recovery,
.unprepare_recovery = davinci_i2c_unprepare_recovery,
};
@@ -567,9 +566,6 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
}
ret = num;
-#ifdef CONFIG_CPU_FREQ
- complete(&dev->xfr_complete);
-#endif
out:
pm_runtime_mark_last_busy(dev->dev);
@@ -717,13 +713,15 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
struct davinci_i2c_dev *dev;
dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
+
+ i2c_lock_adapter(&dev->adapter);
if (val == CPUFREQ_PRECHANGE) {
- wait_for_completion(&dev->xfr_complete);
davinci_i2c_reset_ctrl(dev, 0);
} else if (val == CPUFREQ_POSTCHANGE) {
i2c_davinci_calc_clk_dividers(dev);
davinci_i2c_reset_ctrl(dev, 1);
}
+ i2c_unlock_adapter(&dev->adapter);
return 0;
}
@@ -769,6 +767,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
struct davinci_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem;
+ struct i2c_bus_recovery_info *rinfo;
int r, irq;
irq = platform_get_irq(pdev, 0);
@@ -789,9 +788,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
}
init_completion(&dev->cmd_complete);
-#ifdef CONFIG_CPU_FREQ
- init_completion(&dev->xfr_complete);
-#endif
+
dev->dev = &pdev->dev;
dev->irq = irq;
dev->pdata = dev_get_platdata(&pdev->dev);
@@ -868,10 +865,20 @@ static int davinci_i2c_probe(struct platform_device *pdev)
if (dev->pdata->has_pfunc)
adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;
- else if (dev->pdata->scl_pin) {
- adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info;
- adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin;
- adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin;
+ else if (dev->pdata->gpio_recovery) {
+ rinfo = &davinci_i2c_gpio_recovery_info;
+ adap->bus_recovery_info = rinfo;
+ rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl",
+ GPIOD_OUT_HIGH_OPEN_DRAIN);
+ if (IS_ERR(rinfo->scl_gpiod)) {
+ r = PTR_ERR(rinfo->scl_gpiod);
+ goto err_unuse_clocks;
+ }
+ rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
+ if (IS_ERR(rinfo->sda_gpiod)) {
+ r = PTR_ERR(rinfo->sda_gpiod);
+ goto err_unuse_clocks;
+ }
}
adap->nr = pdev->id;
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index d1a69372432f..27ebd90de43b 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -21,6 +21,7 @@
* ----------------------------------------------------------------------------
*
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/errno.h>
@@ -185,6 +186,19 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
return dev->get_clk_rate_khz(dev);
}
+int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare)
+{
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+
+ if (prepare)
+ return clk_prepare_enable(dev->clk);
+
+ clk_disable_unprepare(dev->clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk);
+
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
{
int ret;
@@ -217,7 +231,11 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
if (timeout <= 0) {
dev_warn(dev->dev, "timeout waiting for bus ready\n");
- return -ETIMEDOUT;
+ i2c_recover_bus(&dev->adapter);
+
+ if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY)
+ return -ETIMEDOUT;
+ return 0;
}
timeout--;
usleep_range(1000, 1100);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9fee4c054d3d..8707c76b2fee 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -284,6 +284,7 @@ struct dw_i2c_dev {
void (*disable_int)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev);
int mode;
+ struct i2c_bus_recovery_info rinfo;
};
#define ACCESS_SWAP 0x00000001
@@ -299,6 +300,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable);
void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable);
unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
+int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 418c233075d3..ae691884d071 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -25,11 +25,13 @@
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/export.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include "i2c-designware-core.h"
@@ -443,6 +445,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
dev_err(dev->dev, "controller timed out\n");
/* i2c_dw_init implicitly disables the adapter */
+ i2c_recover_bus(&dev->adapter);
i2c_dw_init_master(dev);
ret = -ETIMEDOUT;
goto done;
@@ -613,6 +616,56 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
return IRQ_HANDLED;
}
+static void i2c_dw_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ i2c_dw_disable(dev);
+ reset_control_assert(dev->rst);
+ i2c_dw_prepare_clk(dev, false);
+}
+
+static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ i2c_dw_prepare_clk(dev, true);
+ reset_control_deassert(dev->rst);
+ i2c_dw_init_master(dev);
+}
+
+static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
+{
+ struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
+ struct i2c_adapter *adap = &dev->adapter;
+ struct gpio_desc *gpio;
+ int r;
+
+ gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpio)) {
+ r = PTR_ERR(gpio);
+ if (r == -ENOENT)
+ return 0;
+ return r;
+ }
+ rinfo->scl_gpiod = gpio;
+
+ gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN);
+ if (IS_ERR(gpio))
+ return PTR_ERR(gpio);
+ rinfo->sda_gpiod = gpio;
+
+ rinfo->recover_bus = i2c_generic_scl_recovery;
+ rinfo->prepare_recovery = i2c_dw_prepare_recovery;
+ rinfo->unprepare_recovery = i2c_dw_unprepare_recovery;
+ adap->bus_recovery_info = rinfo;
+
+ dev_info(dev->dev, "running with gpio recovery mode! scl%s",
+ rinfo->sda_gpiod ? ",sda" : "");
+
+ return 0;
+}
+
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
@@ -652,6 +705,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
return ret;
}
+ ret = i2c_dw_init_recovery_info(dev);
+ if (ret)
+ return ret;
+
/*
* Increment PM usage count during adapter registration in order to
* avoid possible spurious runtime suspend when adapter device is
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 153b947702c5..5660daf6c92e 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -202,29 +202,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev)
DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED;
dev->mode = DW_IC_SLAVE;
-
- switch (dev->clk_freq) {
- case 100000:
- dev->slave_cfg |= DW_IC_CON_SPEED_STD;
- break;
- case 3400000:
- dev->slave_cfg |= DW_IC_CON_SPEED_HIGH;
- break;
- default:
- dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
- }
-}
-
-static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
-{
- if (IS_ERR(i_dev->clk))
- return PTR_ERR(i_dev->clk);
-
- if (prepare)
- return clk_prepare_enable(i_dev->clk);
-
- clk_disable_unprepare(i_dev->clk);
- return 0;
}
static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
@@ -356,7 +333,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
i2c_dw_configure_master(dev);
dev->clk = devm_clk_get(&pdev->dev, NULL);
- if (!i2c_dw_plat_prepare_clk(dev, true)) {
+ if (!i2c_dw_prepare_clk(dev, true)) {
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
if (!dev->sda_hold_time && ht)
@@ -472,7 +449,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i_dev->disable(i_dev);
- i2c_dw_plat_prepare_clk(i_dev, false);
+ i2c_dw_prepare_clk(i_dev, false);
return 0;
}
@@ -481,7 +458,7 @@ static int dw_i2c_plat_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
- i2c_dw_plat_prepare_clk(i_dev, true);
+ i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev);
return 0;
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index ea9578ab19a1..d42558d1b002 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -51,9 +51,7 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
*/
static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
{
- u32 sda_falling_time, scl_falling_time;
u32 reg, comp_param1;
- u32 hcnt, lcnt;
int ret;
ret = i2c_dw_acquire_lock(dev);
@@ -79,68 +77,6 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
/* Disable the adapter. */
__i2c_dw_enable_and_wait(dev, false);
- /* Set standard and fast speed deviders for high/low periods. */
- sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
- scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
-
- /* Set SCL timing parameters for standard-mode. */
- if (dev->ss_hcnt && dev->ss_lcnt) {
- hcnt = dev->ss_hcnt;
- lcnt = dev->ss_lcnt;
- } else {
- hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
- 4000, /* tHD;STA = tHIGH = 4.0 us */
- sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
- 4700, /* tLOW = 4.7 us */
- scl_falling_time,
- 0); /* No offset */
- }
- dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
- dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
- dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
-
- /* Set SCL timing parameters for fast-mode or fast-mode plus. */
- if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) {
- hcnt = dev->fp_hcnt;
- lcnt = dev->fp_lcnt;
- } else if (dev->fs_hcnt && dev->fs_lcnt) {
- hcnt = dev->fs_hcnt;
- lcnt = dev->fs_lcnt;
- } else {
- hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
- 600, /* tHD;STA = tHIGH = 0.6 us */
- sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
- 1300, /* tLOW = 1.3 us */
- scl_falling_time,
- 0); /* No offset */
- }
- dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
- dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
- dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
-
- if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) ==
- DW_IC_CON_SPEED_HIGH) {
- if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
- != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) {
- dev_err(dev->dev, "High Speed not supported!\n");
- dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK;
- dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
- } else if (dev->hs_hcnt && dev->hs_lcnt) {
- hcnt = dev->hs_hcnt;
- lcnt = dev->hs_lcnt;
- dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
- dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
- dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
- hcnt, lcnt);
- }
- }
-
/* Configure SDA Hold Time if required. */
reg = dw_readl(dev, DW_IC_COMP_VERSION);
if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 3855e0b11877..b02428498f6d 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -170,7 +170,7 @@
#define HSI2C_HS_TX_CLOCK 1000000
#define HSI2C_FS_TX_CLOCK 100000
-#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000))
+#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100))
#define HSI2C_EXYNOS7 BIT(0)
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index d80ea6ce91bb..58abb3eced58 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -7,6 +7,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/debugfs.h>
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/i2c-gpio.h>
@@ -23,6 +25,9 @@ struct i2c_gpio_private_data {
struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata;
+#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
+ struct dentry *debug_dir;
+#endif
};
/*
@@ -34,7 +39,7 @@ static void i2c_gpio_setsda_val(void *data, int state)
{
struct i2c_gpio_private_data *priv = data;
- gpiod_set_value(priv->sda, state);
+ gpiod_set_value_cansleep(priv->sda, state);
}
/*
@@ -47,23 +52,125 @@ static void i2c_gpio_setscl_val(void *data, int state)
{
struct i2c_gpio_private_data *priv = data;
- gpiod_set_value(priv->scl, state);
+ gpiod_set_value_cansleep(priv->scl, state);
}
static int i2c_gpio_getsda(void *data)
{
struct i2c_gpio_private_data *priv = data;
- return gpiod_get_value(priv->sda);
+ return gpiod_get_value_cansleep(priv->sda);
}
static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_private_data *priv = data;
- return gpiod_get_value(priv->scl);
+ return gpiod_get_value_cansleep(priv->scl);
+}
+
+#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
+static struct dentry *i2c_gpio_debug_dir;
+
+#define setsda(bd, val) ((bd)->setsda((bd)->data, val))
+#define setscl(bd, val) ((bd)->setscl((bd)->data, val))
+#define getsda(bd) ((bd)->getsda((bd)->data))
+#define getscl(bd) ((bd)->getscl((bd)->data))
+
+#define WIRE_ATTRIBUTE(wire) \
+static int fops_##wire##_get(void *data, u64 *val) \
+{ \
+ struct i2c_gpio_private_data *priv = data; \
+ \
+ i2c_lock_adapter(&priv->adap); \
+ *val = get##wire(&priv->bit_data); \
+ i2c_unlock_adapter(&priv->adap); \
+ return 0; \
+} \
+static int fops_##wire##_set(void *data, u64 val) \
+{ \
+ struct i2c_gpio_private_data *priv = data; \
+ \
+ i2c_lock_adapter(&priv->adap); \
+ set##wire(&priv->bit_data, val); \
+ i2c_unlock_adapter(&priv->adap); \
+ return 0; \
+} \
+DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n")
+
+WIRE_ATTRIBUTE(scl);
+WIRE_ATTRIBUTE(sda);
+
+static int fops_incomplete_transfer_set(void *data, u64 addr)
+{
+ struct i2c_gpio_private_data *priv = data;
+ struct i2c_algo_bit_data *bit_data = &priv->bit_data;
+ int i, pattern;
+
+ if (addr > 0x7f)
+ return -EINVAL;
+
+ /* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */
+ pattern = (addr << 2) | 3;
+
+ i2c_lock_adapter(&priv->adap);
+
+ /* START condition */
+ setsda(bit_data, 0);
+ udelay(bit_data->udelay);
+
+ /* Send ADDR+RD, request ACK, don't send STOP */
+ for (i = 8; i >= 0; i--) {
+ setscl(bit_data, 0);
+ udelay(bit_data->udelay / 2);
+ setsda(bit_data, (pattern >> i) & 1);
+ udelay((bit_data->udelay + 1) / 2);
+ setscl(bit_data, 1);
+ udelay(bit_data->udelay);
+ }
+
+ i2c_unlock_adapter(&priv->adap);
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n");
+
+static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
+{
+ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev);
+
+ /*
+ * If there will be a debugfs-dir per i2c adapter somewhen, put the
+ * 'fault-injector' dir there. Until then, we have a global dir with
+ * all adapters as subdirs.
+ */
+ if (!i2c_gpio_debug_dir) {
+ i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL);
+ if (!i2c_gpio_debug_dir)
+ return;
+ }
+
+ priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir);
+ 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);
+ debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir,
+ priv, &fops_incomplete_transfer);
}
+static void i2c_gpio_fault_injector_exit(struct platform_device *pdev)
+{
+ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev);
+
+ debugfs_remove_recursive(priv->debug_dir);
+}
+#else
+static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {}
+static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {}
+#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/
+
static void of_i2c_gpio_get_props(struct device_node *np,
struct i2c_gpio_platform_data *pdata)
{
@@ -179,6 +286,9 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (IS_ERR(priv->scl))
return PTR_ERR(priv->scl);
+ if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl))
+ dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing");
+
bit_data->setsda = i2c_gpio_setsda_val;
bit_data->setscl = i2c_gpio_setscl_val;
@@ -228,6 +338,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
pdata->scl_is_output_only
? ", no clock stretching" : "");
+ i2c_gpio_fault_injector_init(pdev);
+
return 0;
}
@@ -236,6 +348,8 @@ static int i2c_gpio_remove(struct platform_device *pdev)
struct i2c_gpio_private_data *priv;
struct i2c_adapter *adap;
+ i2c_gpio_fault_injector_exit(pdev);
+
priv = platform_get_drvdata(pdev);
adap = &priv->adap;
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index e86801a63120..e6da2c7a9a3e 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -30,6 +30,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -90,6 +91,8 @@
#define FAST_PLUS_MAX_BITRATE 3400000
#define HIGHSPEED_MAX_BITRATE 5000000
+#define I2C_PM_TIMEOUT 10 /* ms */
+
enum lpi2c_imx_mode {
STANDARD, /* 100+Kbps */
FAST, /* 400+Kbps */
@@ -274,8 +277,8 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
unsigned int temp;
int ret;
- ret = clk_enable(lpi2c_imx->clk);
- if (ret)
+ ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
+ if (ret < 0)
return ret;
temp = MCR_RST;
@@ -284,7 +287,7 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
ret = lpi2c_imx_config(lpi2c_imx);
if (ret)
- goto clk_disable;
+ goto rpm_put;
temp = readl(lpi2c_imx->base + LPI2C_MCR);
temp |= MCR_MEN;
@@ -292,8 +295,9 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
return 0;
-clk_disable:
- clk_disable(lpi2c_imx->clk);
+rpm_put:
+ pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
return ret;
}
@@ -306,7 +310,8 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
temp &= ~MCR_MEN;
writel(temp, lpi2c_imx->base + LPI2C_MCR);
- clk_disable(lpi2c_imx->clk);
+ pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
return 0;
}
@@ -606,22 +611,31 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
return ret;
}
+ pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
temp = readl(lpi2c_imx->base + LPI2C_PARAM);
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
- clk_disable(lpi2c_imx->clk);
-
ret = i2c_add_adapter(&lpi2c_imx->adapter);
if (ret)
- goto clk_unprepare;
+ goto rpm_disable;
+
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
return 0;
-clk_unprepare:
- clk_unprepare(lpi2c_imx->clk);
+rpm_disable:
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
return ret;
}
@@ -632,28 +646,48 @@ static int lpi2c_imx_remove(struct platform_device *pdev)
i2c_del_adapter(&lpi2c_imx->adapter);
- clk_unprepare(lpi2c_imx->clk);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
-static int lpi2c_imx_suspend(struct device *dev)
+static int lpi2c_runtime_suspend(struct device *dev)
{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(lpi2c_imx->clk);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
-static int lpi2c_imx_resume(struct device *dev)
+static int lpi2c_runtime_resume(struct device *dev)
{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+ int ret;
+
pinctrl_pm_select_default_state(dev);
+ ret = clk_prepare_enable(lpi2c_imx->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
+ return ret;
+ }
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(imx_lpi2c_pm, lpi2c_imx_suspend, lpi2c_imx_resume);
+static const struct dev_pm_ops lpi2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
+ lpi2c_runtime_resume, NULL)
+};
+#define IMX_LPI2C_PM (&lpi2c_pm_ops)
+#else
+#define IMX_LPI2C_PM NULL
+#endif
static struct platform_driver lpi2c_imx_driver = {
.probe = lpi2c_imx_probe,
@@ -661,7 +695,7 @@ static struct platform_driver lpi2c_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = lpi2c_imx_of_match,
- .pm = &imx_lpi2c_pm,
+ .pm = IMX_LPI2C_PM,
},
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index f96830ffd9f1..999557729ad2 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -37,6 +37,7 @@
#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -46,7 +47,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
-#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h>
@@ -1006,26 +1006,26 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
"gpio");
- rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0);
- rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0);
+ rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
+ rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH);
- if (rinfo->sda_gpio == -EPROBE_DEFER ||
- rinfo->scl_gpio == -EPROBE_DEFER) {
+ if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
+ PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
- } else if (!gpio_is_valid(rinfo->sda_gpio) ||
- !gpio_is_valid(rinfo->scl_gpio) ||
+ } else if (IS_ERR(rinfo->sda_gpiod) ||
+ IS_ERR(rinfo->scl_gpiod) ||
IS_ERR(i2c_imx->pinctrl_pins_default) ||
IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
dev_dbg(&pdev->dev, "recovery information incomplete\n");
return 0;
}
- dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n",
- rinfo->scl_gpio, rinfo->sda_gpio);
+ dev_dbg(&pdev->dev, "using scl%s for recovery\n",
+ rinfo->sda_gpiod ? ",sda" : "");
rinfo->prepare_recovery = i2c_imx_prepare_recovery;
rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
- rinfo->recover_bus = i2c_generic_gpio_recovery;
+ rinfo->recover_bus = i2c_generic_scl_recovery;
i2c_imx->adapter.bus_recovery_info = rinfo;
return 0;
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index b51adffa4841..0d1c3ec8cb40 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -172,7 +172,7 @@ struct ismt_priv {
dma_addr_t io_rng_dma; /* descriptor HW base addr */
u8 head; /* ring buffer head pointer */
struct completion cmp; /* interrupt completion */
- u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */
+ u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */
};
/**
@@ -320,10 +320,12 @@ static int ismt_process_desc(const struct ismt_desc *desc,
struct ismt_priv *priv, int size,
char read_write)
{
- u8 *dma_buffer = priv->dma_buffer;
+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);
dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n");
__ismt_desc_dump(&priv->pci_dev->dev, desc);
+ ismt_gen_reg_dump(priv);
+ ismt_mstr_reg_dump(priv);
if (desc->status & ISMT_DESC_SCS) {
if (read_write == I2C_SMBUS_WRITE &&
@@ -393,11 +395,12 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
struct ismt_desc *desc;
struct ismt_priv *priv = i2c_get_adapdata(adap);
struct device *dev = &priv->pci_dev->dev;
+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);
desc = &priv->hw[priv->head];
/* Initialize the DMA buffer */
- memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer));
+ memset(priv->buffer, 0, sizeof(priv->buffer));
/* Initialize the descriptor */
memset(desc, 0, sizeof(struct ismt_desc));
@@ -446,8 +449,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->wr_len_cmd = 2;
dma_size = 2;
dma_direction = DMA_TO_DEVICE;
- priv->dma_buffer[0] = command;
- priv->dma_buffer[1] = data->byte;
+ dma_buffer[0] = command;
+ dma_buffer[1] = data->byte;
} else {
/* Read Byte */
dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n");
@@ -466,9 +469,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->wr_len_cmd = 3;
dma_size = 3;
dma_direction = DMA_TO_DEVICE;
- priv->dma_buffer[0] = command;
- priv->dma_buffer[1] = data->word & 0xff;
- priv->dma_buffer[2] = data->word >> 8;
+ dma_buffer[0] = command;
+ dma_buffer[1] = data->word & 0xff;
+ dma_buffer[2] = data->word >> 8;
} else {
/* Read Word */
dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n");
@@ -486,9 +489,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->rd_len = 2;
dma_size = 3;
dma_direction = DMA_BIDIRECTIONAL;
- priv->dma_buffer[0] = command;
- priv->dma_buffer[1] = data->word & 0xff;
- priv->dma_buffer[2] = data->word >> 8;
+ dma_buffer[0] = command;
+ dma_buffer[1] = data->word & 0xff;
+ dma_buffer[2] = data->word >> 8;
break;
case I2C_SMBUS_BLOCK_DATA:
@@ -499,8 +502,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
dma_direction = DMA_TO_DEVICE;
desc->wr_len_cmd = dma_size;
desc->control |= ISMT_DESC_BLK;
- priv->dma_buffer[0] = command;
- memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1);
+ dma_buffer[0] = command;
+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
} else {
/* Block Read */
dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n");
@@ -527,8 +530,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
dma_direction = DMA_TO_DEVICE;
desc->wr_len_cmd = dma_size;
desc->control |= ISMT_DESC_I2C;
- priv->dma_buffer[0] = command;
- memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1);
+ dma_buffer[0] = command;
+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
} else {
/* i2c Block Read */
dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n");
@@ -557,23 +560,22 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
if (dma_size != 0) {
dev_dbg(dev, " dev=%p\n", dev);
dev_dbg(dev, " data=%p\n", data);
- dev_dbg(dev, " dma_buffer=%p\n", priv->dma_buffer);
+ dev_dbg(dev, " dma_buffer=%p\n", dma_buffer);
dev_dbg(dev, " dma_size=%d\n", dma_size);
dev_dbg(dev, " dma_direction=%d\n", dma_direction);
dma_addr = dma_map_single(dev,
- priv->dma_buffer,
+ dma_buffer,
dma_size,
dma_direction);
if (dma_mapping_error(dev, dma_addr)) {
dev_err(dev, "Error in mapping dma buffer %p\n",
- priv->dma_buffer);
+ dma_buffer);
return -EIO;
}
- dev_dbg(dev, " dma_addr = 0x%016llX\n",
- (unsigned long long)dma_addr);
+ dev_dbg(dev, " dma_addr = %pad\n", &dma_addr);
desc->dptr_low = lower_32_bits(dma_addr);
desc->dptr_high = upper_32_bits(dma_addr);
diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
index 88d15b92ec35..90f5d0407d73 100644
--- a/drivers/i2c/busses/i2c-meson.c
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/types.h>
@@ -57,6 +58,10 @@ enum {
STATE_WRITE,
};
+struct meson_i2c_data {
+ unsigned char div_factor;
+};
+
/**
* struct meson_i2c - Meson I2C device private data
*
@@ -64,7 +69,6 @@ enum {
* @dev: Pointer to device structure
* @regs: Base address of the device memory mapped registers
* @clk: Pointer to clock structure
- * @irq: IRQ number
* @msg: Pointer to the current I2C message
* @state: Current state in the driver state machine
* @last: Flag set for the last message in the transfer
@@ -75,6 +79,7 @@ enum {
* @done: Completion used to wait for transfer termination
* @tokens: Sequence of tokens to be written to the device
* @num_tokens: Number of tokens
+ * @data: Pointer to the controlller's platform data
*/
struct meson_i2c {
struct i2c_adapter adap;
@@ -93,6 +98,8 @@ struct meson_i2c {
struct completion done;
u32 tokens[2];
int num_tokens;
+
+ const struct meson_i2c_data *data;
};
static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask,
@@ -128,7 +135,7 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
unsigned long clk_rate = clk_get_rate(i2c->clk);
unsigned int div;
- div = DIV_ROUND_UP(clk_rate, freq * 4);
+ div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor);
/* clock divider has 12 bits */
if (div >= (1 << 12)) {
@@ -376,6 +383,9 @@ static int meson_i2c_probe(struct platform_device *pdev)
spin_lock_init(&i2c->lock);
init_completion(&i2c->done);
+ i2c->data = (const struct meson_i2c_data *)
+ of_device_get_match_data(&pdev->dev);
+
i2c->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "can't get device clock\n");
@@ -440,11 +450,25 @@ static int meson_i2c_remove(struct platform_device *pdev)
return 0;
}
+static const struct meson_i2c_data i2c_meson6_data = {
+ .div_factor = 4,
+};
+
+static const struct meson_i2c_data i2c_gxbb_data = {
+ .div_factor = 4,
+};
+
+static const struct meson_i2c_data i2c_axg_data = {
+ .div_factor = 3,
+};
+
static const struct of_device_id meson_i2c_match[] = {
- { .compatible = "amlogic,meson6-i2c" },
- { .compatible = "amlogic,meson-gxbb-i2c" },
- { },
+ { .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data },
+ { .compatible = "amlogic,meson-gxbb-i2c", .data = &i2c_gxbb_data },
+ { .compatible = "amlogic,meson-axg-i2c", .data = &i2c_axg_data },
+ {},
};
+
MODULE_DEVICE_TABLE(of, meson_i2c_match);
static struct platform_driver meson_i2c_driver = {
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 950a9d74f54d..d94f05c8b8b7 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -78,9 +78,7 @@ struct mpc_i2c_divider {
};
struct mpc_i2c_data {
- void (*setup)(struct device_node *node, struct mpc_i2c *i2c,
- u32 clock, u32 prescaler);
- u32 prescaler;
+ void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock);
};
static inline void writeccr(struct mpc_i2c *i2c, u32 x)
@@ -201,7 +199,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
};
static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
- int prescaler, u32 *real_clk)
+ u32 *real_clk)
{
const struct mpc_i2c_divider *div = NULL;
unsigned int pvr = mfspr(SPRN_PVR);
@@ -236,7 +234,7 @@ static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
static void mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+ u32 clock)
{
int ret, fdr;
@@ -246,7 +244,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
return;
}
- ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk);
+ ret = mpc_i2c_get_fdr_52xx(node, clock, &i2c->real_clk);
fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
@@ -258,7 +256,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
static void mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+ u32 clock)
{
}
#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
@@ -266,7 +264,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
#ifdef CONFIG_PPC_MPC512x
static void mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+ u32 clock)
{
struct device_node *node_ctrl;
void __iomem *ctrl;
@@ -289,12 +287,12 @@ static void mpc_i2c_setup_512x(struct device_node *node,
}
/* The clock setup for the 52xx works also fine for the 512x */
- mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
+ mpc_i2c_setup_52xx(node, i2c, clock);
}
#else /* CONFIG_PPC_MPC512x */
static void mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+ u32 clock)
{
}
#endif /* CONFIG_PPC_MPC512x */
@@ -332,14 +330,18 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
if (prop) {
/*
* Map and check POR Device Status Register 2
- * (PORDEVSR2) at 0xE0014
+ * (PORDEVSR2) at 0xE0014. Note than while MPC8533
+ * and MPC8544 indicate SEC frequency ratio
+ * configuration as bit 26 in PORDEVSR2, other MPC8xxx
+ * parts may store it differently or may not have it
+ * at all.
*/
reg = ioremap(get_immrbase() + *prop + 0x14, 0x4);
if (!reg)
printk(KERN_ERR
"Error: couldn't map PORDEVSR2\n");
else
- val = in_be32(reg) & 0x00000080; /* sec-cfg */
+ val = in_be32(reg) & 0x00000020; /* sec-cfg */
iounmap(reg);
}
}
@@ -350,7 +352,11 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
static u32 mpc_i2c_get_prescaler_8xxx(void)
{
- /* mpc83xx and mpc82xx all have prescaler 1 */
+ /*
+ * According to the AN2919 all MPC824x have prescaler 1, while MPC83xx
+ * may have prescaler 1, 2, or 3, depending on the power-on
+ * configuration.
+ */
u32 prescaler = 1;
/* mpc85xx */
@@ -367,6 +373,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void)
|| (SVR_SOC_VER(svr) == SVR_8610))
/* the above 85xx SoCs have prescaler 1 */
prescaler = 1;
+ else if ((SVR_SOC_VER(svr) == SVR_8533)
+ || (SVR_SOC_VER(svr) == SVR_8544))
+ /* the above 85xx SoCs have prescaler 3 or 2 */
+ prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
else
/* all the other 85xx have prescaler 2 */
prescaler = 2;
@@ -376,9 +386,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void)
}
static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
- u32 prescaler, u32 *real_clk)
+ u32 *real_clk)
{
const struct mpc_i2c_divider *div = NULL;
+ u32 prescaler = mpc_i2c_get_prescaler_8xxx();
u32 divider;
int i;
@@ -388,12 +399,6 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
return -EINVAL;
}
- /* Determine proper divider value */
- if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
- prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
- if (!prescaler)
- prescaler = mpc_i2c_get_prescaler_8xxx();
-
divider = fsl_get_sys_freq() / clock / prescaler;
pr_debug("I2C: src_clock=%d clock=%d divider=%d\n",
@@ -415,7 +420,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
static void mpc_i2c_setup_8xxx(struct device_node *node,
struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+ u32 clock)
{
int ret, fdr;
@@ -426,7 +431,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node,
return;
}
- ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->real_clk);
+ ret = mpc_i2c_get_fdr_8xxx(node, clock, &i2c->real_clk);
fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
@@ -440,7 +445,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node,
#else /* !CONFIG_FSL_SOC */
static void mpc_i2c_setup_8xxx(struct device_node *node,
struct mpc_i2c *i2c,
- u32 clock, u32 prescaler)
+ u32 clock)
{
}
#endif /* CONFIG_FSL_SOC */
@@ -711,11 +716,11 @@ static int fsl_i2c_probe(struct platform_device *op)
if (match->data) {
const struct mpc_i2c_data *data = match->data;
- data->setup(op->dev.of_node, i2c, clock, data->prescaler);
+ data->setup(op->dev.of_node, i2c, clock);
} else {
/* Backwards compatibility */
if (of_get_property(op->dev.of_node, "dfsrr", NULL))
- mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0);
+ mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock);
}
prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen);
@@ -813,12 +818,10 @@ static const struct mpc_i2c_data mpc_i2c_data_8313 = {
static const struct mpc_i2c_data mpc_i2c_data_8543 = {
.setup = mpc_i2c_setup_8xxx,
- .prescaler = 2,
};
static const struct mpc_i2c_data mpc_i2c_data_8544 = {
.setup = mpc_i2c_setup_8xxx,
- .prescaler = 3,
};
static const struct of_device_id mpc_i2c_of_match[] = {
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 09d288ce0ddb..cf23a746cc17 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -61,6 +61,7 @@
#define I2C_DMA_HARD_RST 0x0002
#define I2C_DMA_4G_MODE 0x0001
+#define I2C_DEFAULT_CLK_DIV 5
#define I2C_DEFAULT_SPEED 100000 /* hz */
#define MAX_FS_MODE_SPEED 400000
#define MAX_HS_MODE_SPEED 3400000
@@ -127,6 +128,7 @@ enum I2C_REGS_OFFSET {
OFFSET_DEBUGSTAT = 0x64,
OFFSET_DEBUGCTRL = 0x68,
OFFSET_TRANSFER_LEN_AUX = 0x6c,
+ OFFSET_CLOCK_DIV = 0x70,
};
struct mtk_i2c_compatible {
@@ -136,6 +138,7 @@ struct mtk_i2c_compatible {
unsigned char auto_restart: 1;
unsigned char aux_len_reg: 1;
unsigned char support_33bits: 1;
+ unsigned char timing_adjust: 1;
};
struct mtk_i2c {
@@ -176,6 +179,15 @@ static const struct i2c_adapter_quirks mt7622_i2c_quirks = {
.max_num_msgs = 255,
};
+static const struct mtk_i2c_compatible mt2712_compat = {
+ .pmic_i2c = 0,
+ .dcm = 1,
+ .auto_restart = 1,
+ .aux_len_reg = 1,
+ .support_33bits = 1,
+ .timing_adjust = 1,
+};
+
static const struct mtk_i2c_compatible mt6577_compat = {
.quirks = &mt6577_i2c_quirks,
.pmic_i2c = 0,
@@ -183,6 +195,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
.auto_restart = 0,
.aux_len_reg = 0,
.support_33bits = 0,
+ .timing_adjust = 0,
};
static const struct mtk_i2c_compatible mt6589_compat = {
@@ -192,6 +205,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
.auto_restart = 0,
.aux_len_reg = 0,
.support_33bits = 0,
+ .timing_adjust = 0,
};
static const struct mtk_i2c_compatible mt7622_compat = {
@@ -201,6 +215,7 @@ static const struct mtk_i2c_compatible mt7622_compat = {
.auto_restart = 1,
.aux_len_reg = 1,
.support_33bits = 0,
+ .timing_adjust = 0,
};
static const struct mtk_i2c_compatible mt8173_compat = {
@@ -209,9 +224,11 @@ static const struct mtk_i2c_compatible mt8173_compat = {
.auto_restart = 1,
.aux_len_reg = 1,
.support_33bits = 1,
+ .timing_adjust = 0,
};
static const struct of_device_id mtk_i2c_of_match[] = {
+ { .compatible = "mediatek,mt2712-i2c", .data = &mt2712_compat },
{ .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
{ .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
@@ -271,6 +288,9 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
if (i2c->dev_comp->dcm)
writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN);
+ if (i2c->dev_comp->timing_adjust)
+ writew(I2C_DEFAULT_CLK_DIV - 1, i2c->base + OFFSET_CLOCK_DIV);
+
writew(i2c->timing_reg, i2c->base + OFFSET_TIMING);
writew(i2c->high_speed_reg, i2c->base + OFFSET_HS);
@@ -725,10 +745,6 @@ static int mtk_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
- ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
- if (ret)
- return -EINVAL;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base))
@@ -759,6 +775,13 @@ static int mtk_i2c_probe(struct platform_device *pdev)
i2c->adap.timeout = 2 * HZ;
i2c->adap.retries = 1;
+ ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
+ if (ret)
+ return -EINVAL;
+
+ if (i2c->dev_comp->timing_adjust)
+ i2c->clk_src_div *= I2C_DEFAULT_CLK_DIV;
+
if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c)
return -EINVAL;
@@ -838,10 +861,19 @@ static int mtk_i2c_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int mtk_i2c_resume(struct device *dev)
{
+ int ret;
struct mtk_i2c *i2c = dev_get_drvdata(dev);
+ ret = mtk_i2c_clock_enable(i2c);
+ if (ret) {
+ dev_err(dev, "clock enable failed!\n");
+ return ret;
+ }
+
mtk_i2c_init_hw(i2c);
+ mtk_i2c_clock_disable(i2c);
+
return 0;
}
#endif
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index a832c45276a4..440fe4a96e68 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -135,6 +135,7 @@ struct mv64xxx_i2c_data {
u32 freq_m;
u32 freq_n;
struct clk *clk;
+ struct clk *reg_clk;
wait_queue_head_t waitq;
spinlock_t lock;
struct i2c_msg *msg;
@@ -894,13 +895,20 @@ mv64xxx_i2c_probe(struct platform_device *pd)
init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock);
- /* Not all platforms have a clk */
+ /* Not all platforms have clocks */
drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (!IS_ERR(drv_data->clk))
clk_prepare_enable(drv_data->clk);
+ drv_data->reg_clk = devm_clk_get(&pd->dev, "reg");
+ if (IS_ERR(drv_data->reg_clk) &&
+ PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (!IS_ERR(drv_data->reg_clk))
+ clk_prepare_enable(drv_data->reg_clk);
+
drv_data->irq = platform_get_irq(pd, 0);
if (pdata) {
@@ -950,9 +958,8 @@ exit_free_irq:
exit_reset:
reset_control_assert(drv_data->rstc);
exit_clk:
- /* Not all platforms have a clk */
- if (!IS_ERR(drv_data->clk))
- clk_disable_unprepare(drv_data->clk);
+ clk_disable_unprepare(drv_data->reg_clk);
+ clk_disable_unprepare(drv_data->clk);
return rc;
}
@@ -965,9 +972,8 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
reset_control_assert(drv_data->rstc);
- /* Not all platforms have a clk */
- if (!IS_ERR(drv_data->clk))
- clk_disable_unprepare(drv_data->clk);
+ clk_disable_unprepare(drv_data->reg_clk);
+ clk_disable_unprepare(drv_data->clk);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index d4e8f1954f23..e617bd600794 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -181,7 +181,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
if (msg->flags & I2C_M_RD) {
- i2c->dma_read = 1;
+ i2c->dma_read = true;
i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
/*
@@ -239,7 +239,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
goto read_init_dma_fail;
}
} else {
- i2c->dma_read = 0;
+ i2c->dma_read = false;
i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
/*
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 15d764afec3b..4159ebcec2bb 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -62,7 +62,7 @@
#define MIE (1 << 3) /* master if enable */
#define TSBE (1 << 2)
#define FSB (1 << 1) /* force stop bit */
-#define ESG (1 << 0) /* en startbit gen */
+#define ESG (1 << 0) /* enable start bit gen */
/* ICSSR (also for ICSIER) */
#define GCAR (1 << 6) /* general call received */
@@ -132,6 +132,7 @@ struct rcar_i2c_priv {
int pos;
u32 icccr;
u32 flags;
+ u8 recovery_icmcr; /* protected by adapter lock */
enum rcar_i2c_type devtype;
struct i2c_client *slave;
@@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
return readl(priv->io + reg);
}
+static int rcar_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(rcar_i2c_read(priv, ICMCR) & FSCL);
+
+};
+
+static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (val)
+ priv->recovery_icmcr |= FSCL;
+ else
+ priv->recovery_icmcr &= ~FSCL;
+
+ rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
+};
+
+/* No get_sda, because the HW only reports its bus free logic, not SDA itself */
+
+static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (val)
+ priv->recovery_icmcr |= FSDA;
+ else
+ priv->recovery_icmcr &= ~FSDA;
+
+ rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
+};
+
+static struct i2c_bus_recovery_info rcar_i2c_bri = {
+ .get_scl = rcar_i2c_get_scl,
+ .set_scl = rcar_i2c_set_scl,
+ .set_sda = rcar_i2c_set_sda,
+ .recover_bus = i2c_generic_scl_recovery,
+};
static void rcar_i2c_init(struct rcar_i2c_priv *priv)
{
/* reset master mode */
@@ -170,7 +211,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
{
- int i;
+ int i, ret;
for (i = 0; i < LOOP_TIMEOUT; i++) {
/* make sure that bus is not busy */
@@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
udelay(1);
}
- return -EBUSY;
+ /* Waiting did not help, try to recover */
+ priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
+ ret = i2c_recover_bus(&priv->adap);
+
+ /* No failure when recovering, so check bus busy bit again */
+ if (ret == 0)
+ ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0;
+
+ return ret;
}
static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t)
@@ -282,7 +331,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read);
/*
- * We don't have a testcase but the HW engineers say that the write order
+ * We don't have a test case but the HW engineers say that the write order
* of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
* it didn't cause a drawback for me, let's rather be safe than sorry.
*/
@@ -359,7 +408,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
int len;
/* Do not use DMA if it's not available or for messages < 8 bytes */
- if (IS_ERR(chan) || msg->len < 8)
+ if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE))
return;
if (read) {
@@ -440,7 +489,7 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
/*
* Try to use DMA to transmit the rest of the data if
- * address transfer pashe just finished.
+ * address transfer phase just finished.
*/
if (msr & MAT)
rcar_i2c_dma(priv);
@@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
adap->retries = 3;
adap->dev.parent = dev;
adap->dev.of_node = dev->of_node;
+ adap->bus_recovery_info = &rcar_i2c_bri;
i2c_set_adapdata(adap, priv);
strlcpy(adap->name, pdev->name, sizeof(adap->name));
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index fe234578380a..e1a18d989f83 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -161,6 +161,7 @@ enum rk3x_i2c_state {
};
/**
+ * struct rk3x_i2c_soc_data:
* @grf_offset: offset inside the grf regmap for setting the i2c type
* @calc_timings: Callback function for i2c timing information calculated
*/
@@ -194,7 +195,7 @@ struct rk3x_i2c_soc_data {
struct rk3x_i2c {
struct i2c_adapter adap;
struct device *dev;
- struct rk3x_i2c_soc_data *soc_data;
+ const struct rk3x_i2c_soc_data *soc_data;
/* Hardware resources */
void __iomem *regs;
@@ -1164,27 +1165,27 @@ static const struct rk3x_i2c_soc_data rk3399_soc_data = {
static const struct of_device_id rk3x_i2c_match[] = {
{
.compatible = "rockchip,rv1108-i2c",
- .data = (void *)&rv1108_soc_data
+ .data = &rv1108_soc_data
},
{
.compatible = "rockchip,rk3066-i2c",
- .data = (void *)&rk3066_soc_data
+ .data = &rk3066_soc_data
},
{
.compatible = "rockchip,rk3188-i2c",
- .data = (void *)&rk3188_soc_data
+ .data = &rk3188_soc_data
},
{
.compatible = "rockchip,rk3228-i2c",
- .data = (void *)&rk3228_soc_data
+ .data = &rk3228_soc_data
},
{
.compatible = "rockchip,rk3288-i2c",
- .data = (void *)&rk3288_soc_data
+ .data = &rk3288_soc_data
},
{
.compatible = "rockchip,rk3399-i2c",
- .data = (void *)&rk3399_soc_data
+ .data = &rk3399_soc_data
},
{},
};
@@ -1207,7 +1208,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
match = of_match_node(rk3x_i2c_match, np);
- i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data;
+ i2c->soc_data = match->data;
/* use common interface to get I2C timing properties */
i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index c03acdf71397..d856bc211715 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -40,21 +40,21 @@
/* BUS: S A8 ACK P(*) */
/* IRQ: DTE WAIT */
/* ICIC: */
-/* ICCR: 0x94 0x90 */
+/* ICCR: 0x94 0x90 */
/* ICDR: A8 */
/* */
/* 1 byte transmit */
/* BUS: S A8 ACK D8(1) ACK P(*) */
/* IRQ: DTE WAIT WAIT */
/* ICIC: -DTE */
-/* ICCR: 0x94 0x90 */
+/* ICCR: 0x94 0x90 */
/* ICDR: A8 D8(1) */
/* */
/* 2 byte transmit */
/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */
/* IRQ: DTE WAIT WAIT WAIT */
/* ICIC: -DTE */
-/* ICCR: 0x94 0x90 */
+/* ICCR: 0x94 0x90 */
/* ICDR: A8 D8(1) D8(2) */
/* */
/* 3 bytes or more, +---------+ gets repeated */
@@ -113,7 +113,6 @@ enum sh_mobile_i2c_op {
OP_TX_FIRST,
OP_TX,
OP_TX_STOP,
- OP_TX_STOP_DATA,
OP_TX_TO_RX,
OP_RX,
OP_RX_STOP,
@@ -145,11 +144,12 @@ struct sh_mobile_i2c_data {
struct dma_chan *dma_rx;
struct scatterlist sg;
enum dma_data_direction dma_direction;
+ u8 *dma_buf;
};
struct sh_mobile_dt_config {
int clks_per_count;
- void (*setup)(struct sh_mobile_i2c_data *pd);
+ int (*setup)(struct sh_mobile_i2c_data *pd);
};
#define IIC_FLAG_HAS_ICIC67 (1 << 0)
@@ -246,36 +246,10 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf)
return (((count_khz * (tHIGH + tf)) + 5000) / 10000);
}
-static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
+static int sh_mobile_i2c_check_timing(struct sh_mobile_i2c_data *pd)
{
- unsigned long i2c_clk_khz;
- u32 tHIGH, tLOW, tf;
- uint16_t max_val;
-
- /* Get clock rate after clock is enabled */
- clk_prepare_enable(pd->clk);
- i2c_clk_khz = clk_get_rate(pd->clk) / 1000;
- clk_disable_unprepare(pd->clk);
- i2c_clk_khz /= pd->clks_per_count;
-
- if (pd->bus_speed == STANDARD_MODE) {
- tLOW = 47; /* tLOW = 4.7 us */
- tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */
- tf = 3; /* tf = 0.3 us */
- } else if (pd->bus_speed == FAST_MODE) {
- tLOW = 13; /* tLOW = 1.3 us */
- tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */
- tf = 3; /* tf = 0.3 us */
- } else {
- dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
- pd->bus_speed);
- return -EINVAL;
- }
-
- pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
- pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
+ u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
- max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
if (pd->iccl > max_val || pd->icch > max_val) {
dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n",
pd->iccl, pd->icch);
@@ -298,35 +272,43 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
return 0;
}
-static void activate_ch(struct sh_mobile_i2c_data *pd)
+static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
{
- /* Wake up device and enable clock */
- pm_runtime_get_sync(pd->dev);
- clk_prepare_enable(pd->clk);
+ unsigned long i2c_clk_khz;
+ u32 tHIGH, tLOW, tf;
- /* Enable channel and configure rx ack */
- iic_set_clr(pd, ICCR, ICCR_ICE, 0);
+ i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count;
- /* Mask all interrupts */
- iic_wr(pd, ICIC, 0);
+ if (pd->bus_speed == STANDARD_MODE) {
+ tLOW = 47; /* tLOW = 4.7 us */
+ tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */
+ tf = 3; /* tf = 0.3 us */
+ } else if (pd->bus_speed == FAST_MODE) {
+ tLOW = 13; /* tLOW = 1.3 us */
+ tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */
+ tf = 3; /* tf = 0.3 us */
+ } else {
+ dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
+ pd->bus_speed);
+ return -EINVAL;
+ }
- /* Set the clock */
- iic_wr(pd, ICCL, pd->iccl & 0xff);
- iic_wr(pd, ICCH, pd->icch & 0xff);
+ pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
+ pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
+
+ return sh_mobile_i2c_check_timing(pd);
}
-static void deactivate_ch(struct sh_mobile_i2c_data *pd)
+static int sh_mobile_i2c_v2_init(struct sh_mobile_i2c_data *pd)
{
- /* Clear/disable interrupts */
- iic_wr(pd, ICSR, 0);
- iic_wr(pd, ICIC, 0);
+ unsigned long clks_per_cycle;
- /* Disable channel */
- iic_set_clr(pd, ICCR, 0, ICCR_ICE);
+ /* L = 5, H = 4, L + H = 9 */
+ clks_per_cycle = clk_get_rate(pd->clk) / pd->bus_speed;
+ pd->iccl = DIV_ROUND_UP(clks_per_cycle * 5 / 9 - 1, pd->clks_per_count);
+ pd->icch = DIV_ROUND_UP(clks_per_cycle * 4 / 9 - 5, pd->clks_per_count);
- /* Disable clock and mark device as idle */
- clk_disable_unprepare(pd->clk);
- pm_runtime_put_sync(pd->dev);
+ return sh_mobile_i2c_check_timing(pd);
}
static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
@@ -350,10 +332,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
case OP_TX: /* write data */
iic_wr(pd, ICDR, data);
break;
- case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */
- iic_wr(pd, ICDR, data);
- /* fallthrough */
- case OP_TX_STOP: /* issue a stop */
+ case OP_TX_STOP: /* issue a stop (or rep_start) */
iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
: ICCR_ICE | ICCR_TRS | ICCR_BBSY);
break;
@@ -387,11 +366,6 @@ static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
return pd->pos == -1;
}
-static bool sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
-{
- return pd->pos == pd->msg->len - 1;
-}
-
static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
unsigned char *buf)
{
@@ -409,20 +383,12 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
unsigned char data;
if (pd->pos == pd->msg->len) {
- /* Send stop if we haven't yet (DMA case) */
- if (pd->send_stop && pd->stop_after_dma)
- i2c_op(pd, OP_TX_STOP, 0);
+ i2c_op(pd, OP_TX_STOP, 0);
return 1;
}
sh_mobile_i2c_get_data(pd, &data);
-
- if (sh_mobile_i2c_is_last_byte(pd))
- i2c_op(pd, OP_TX_STOP_DATA, data);
- else if (sh_mobile_i2c_is_first_byte(pd))
- i2c_op(pd, OP_TX_FIRST, data);
- else
- i2c_op(pd, OP_TX, data);
+ i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, data);
pd->pos++;
return 0;
@@ -464,8 +430,9 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
break;
}
data = i2c_op(pd, OP_RX_STOP_DATA, 0);
- } else
+ } else if (real_pos >= 0) {
data = i2c_op(pd, OP_RX, 0);
+ }
if (real_pos >= 0)
pd->msg->buf[real_pos] = data;
@@ -548,6 +515,8 @@ static void sh_mobile_i2c_dma_callback(void *data)
pd->pos = pd->msg->len;
pd->stop_after_dma = true;
+ i2c_release_dma_safe_msg_buf(pd->msg, pd->dma_buf);
+
iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
}
@@ -608,7 +577,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
if (IS_ERR(chan))
return;
- dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir);
+ dma_addr = dma_map_single(chan->device->dev, pd->dma_buf, pd->msg->len, dir);
if (dma_mapping_error(chan->device->dev, dma_addr)) {
dev_dbg(pd->dev, "dma map failed, using PIO\n");
return;
@@ -651,10 +620,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
if (do_init) {
/* Initialize channel registers */
- iic_set_clr(pd, ICCR, 0, ICCR_ICE);
+ iic_wr(pd, ICCR, ICCR_SCP);
/* Enable channel and configure rx ack */
- iic_set_clr(pd, ICCR, ICCR_ICE, 0);
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
/* Set the clock */
iic_wr(pd, ICCL, pd->iccl & 0xff);
@@ -665,7 +634,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
pd->pos = -1;
pd->sr = 0;
- if (pd->msg->len > 8)
+ pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
+ if (pd->dma_buf)
sh_mobile_i2c_xfer_dma(pd);
/* Enable all interrupts to begin with */
@@ -731,7 +701,8 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
int i;
long timeout;
- activate_ch(pd);
+ /* Wake up device and enable clock */
+ pm_runtime_get_sync(pd->dev);
/* Process all messages */
for (i = 0; i < num; i++) {
@@ -768,11 +739,13 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
break;
}
- deactivate_ch(pd);
+ /* Disable channel */
+ iic_wr(pd, ICCR, ICCR_SCP);
- if (!err)
- err = num;
- return err;
+ /* Disable clock and mark device as idle */
+ pm_runtime_put_sync(pd->dev);
+
+ return err ?: num;
}
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
@@ -789,7 +762,7 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
* r8a7740 chip has lasting errata on I2C I/O pad reset.
* this is work-around for it.
*/
-static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
+static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
{
iic_set_clr(pd, ICCR, ICCR_ICE, 0);
iic_rd(pd, ICCR); /* dummy read */
@@ -810,14 +783,23 @@ static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
udelay(10);
iic_wr(pd, ICCR, ICCR_TRS);
udelay(10);
+
+ return sh_mobile_i2c_init(pd);
}
static const struct sh_mobile_dt_config default_dt_config = {
.clks_per_count = 1,
+ .setup = sh_mobile_i2c_init,
};
static const struct sh_mobile_dt_config fast_clock_dt_config = {
.clks_per_count = 2,
+ .setup = sh_mobile_i2c_init,
+};
+
+static const struct sh_mobile_dt_config v2_freq_calc_dt_config = {
+ .clks_per_count = 2,
+ .setup = sh_mobile_i2c_v2_init,
};
static const struct sh_mobile_dt_config r8a7740_dt_config = {
@@ -828,7 +810,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-r8a7790", .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 },
@@ -910,32 +892,13 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return PTR_ERR(pd->reg);
ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
- pd->bus_speed = ret ? STANDARD_MODE : bus_speed;
+ pd->bus_speed = (ret || !bus_speed) ? STANDARD_MODE : bus_speed;
pd->clks_per_count = 1;
- config = of_device_get_match_data(&dev->dev);
- if (config) {
- pd->clks_per_count = config->clks_per_count;
-
- if (config->setup)
- config->setup(pd);
- }
-
- /* The IIC blocks on SH-Mobile ARM processors
- * come with two new bits in ICIC.
- */
+ /* Newer variants come with two new bits in ICIC */
if (resource_size(res) > 0x17)
pd->flags |= IIC_FLAG_HAS_ICIC67;
- ret = sh_mobile_i2c_init(pd);
- if (ret)
- return ret;
-
- /* Init DMA */
- sg_init_table(&pd->sg, 1);
- pd->dma_direction = DMA_NONE;
- pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
-
/* Enable Runtime PM for this device.
*
* Also tell the Runtime PM core to ignore children
@@ -948,6 +911,24 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
*/
pm_suspend_ignore_children(&dev->dev, true);
pm_runtime_enable(&dev->dev);
+ pm_runtime_get_sync(&dev->dev);
+
+ config = of_device_get_match_data(&dev->dev);
+ if (config) {
+ pd->clks_per_count = config->clks_per_count;
+ ret = config->setup(pd);
+ } else {
+ ret = sh_mobile_i2c_init(pd);
+ }
+
+ pm_runtime_put_sync(&dev->dev);
+ if (ret)
+ return ret;
+
+ /* Init DMA */
+ sg_init_table(&pd->sg, 1);
+ pd->dma_direction = DMA_NONE;
+ pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
/* setup the private data */
adap = &pd->adap;
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index f7829a74140c..5a00bf443d06 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -27,7 +27,7 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/idr.h>
@@ -134,52 +134,22 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
/* i2c bus recovery routines */
static int get_scl_gpio_value(struct i2c_adapter *adap)
{
- return gpio_get_value(adap->bus_recovery_info->scl_gpio);
+ return gpiod_get_value_cansleep(adap->bus_recovery_info->scl_gpiod);
}
static void set_scl_gpio_value(struct i2c_adapter *adap, int val)
{
- gpio_set_value(adap->bus_recovery_info->scl_gpio, val);
+ gpiod_set_value_cansleep(adap->bus_recovery_info->scl_gpiod, val);
}
static int get_sda_gpio_value(struct i2c_adapter *adap)
{
- return gpio_get_value(adap->bus_recovery_info->sda_gpio);
+ return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod);
}
-static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap)
+static void set_sda_gpio_value(struct i2c_adapter *adap, int val)
{
- struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
- struct device *dev = &adap->dev;
- int ret = 0;
-
- ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN |
- GPIOF_OUT_INIT_HIGH, "i2c-scl");
- if (ret) {
- dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio);
- return ret;
- }
-
- if (bri->get_sda) {
- if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) {
- /* work without SDA polling */
- dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n",
- bri->sda_gpio);
- bri->get_sda = NULL;
- }
- }
-
- return ret;
-}
-
-static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap)
-{
- struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
-
- if (bri->get_sda)
- gpio_free(bri->sda_gpio);
-
- gpio_free(bri->scl_gpio);
+ gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val);
}
/*
@@ -190,7 +160,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap)
#define RECOVERY_NDELAY 5000
#define RECOVERY_CLK_CNT 9
-static int i2c_generic_recovery(struct i2c_adapter *adap)
+int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
int i = 0, val = 1, ret = 0;
@@ -199,6 +169,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
bri->prepare_recovery(adap);
bri->set_scl(adap, val);
+ if (bri->set_sda)
+ bri->set_sda(adap, 1);
ndelay(RECOVERY_NDELAY);
/*
@@ -227,33 +199,25 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
if (bri->get_sda && !bri->get_sda(adap))
ret = -EBUSY;
+ /* If all went well, send STOP for a sane bus state. */
+ if (ret == 0 && bri->set_sda) {
+ bri->set_scl(adap, 0);
+ ndelay(RECOVERY_NDELAY / 2);
+ bri->set_sda(adap, 0);
+ ndelay(RECOVERY_NDELAY / 2);
+ bri->set_scl(adap, 1);
+ ndelay(RECOVERY_NDELAY / 2);
+ bri->set_sda(adap, 1);
+ ndelay(RECOVERY_NDELAY / 2);
+ }
+
if (bri->unprepare_recovery)
bri->unprepare_recovery(adap);
return ret;
}
-
-int i2c_generic_scl_recovery(struct i2c_adapter *adap)
-{
- return i2c_generic_recovery(adap);
-}
EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
-int i2c_generic_gpio_recovery(struct i2c_adapter *adap)
-{
- int ret;
-
- ret = i2c_get_gpios_for_recovery(adap);
- if (ret)
- return ret;
-
- ret = i2c_generic_recovery(adap);
- i2c_put_gpios_for_recovery(adap);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery);
-
int i2c_recover_bus(struct i2c_adapter *adap)
{
if (!adap->bus_recovery_info)
@@ -277,21 +241,19 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
goto err;
}
- /* Generic GPIO recovery */
- if (bri->recover_bus == i2c_generic_gpio_recovery) {
- if (!gpio_is_valid(bri->scl_gpio)) {
- err_str = "invalid SCL gpio";
- goto err;
- }
-
- if (gpio_is_valid(bri->sda_gpio))
- bri->get_sda = get_sda_gpio_value;
- else
- bri->get_sda = NULL;
-
+ if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_recovery) {
bri->get_scl = get_scl_gpio_value;
bri->set_scl = set_scl_gpio_value;
- } else if (bri->recover_bus == i2c_generic_scl_recovery) {
+ if (bri->sda_gpiod) {
+ bri->get_sda = get_sda_gpio_value;
+ /* FIXME: add proper flag instead of '0' once available */
+ if (gpiod_get_direction(bri->sda_gpiod) == 0)
+ bri->set_sda = set_sda_gpio_value;
+ }
+ return;
+ }
+
+ if (bri->recover_bus == i2c_generic_scl_recovery) {
/* Generic SCL recovery */
if (!bri->set_scl || !bri->get_scl) {
err_str = "no {get|set}_scl() found";
@@ -1976,63 +1938,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
EXPORT_SYMBOL(i2c_transfer);
/**
- * i2c_master_send - issue a single I2C message in master transmit mode
- * @client: Handle to slave device
- * @buf: Data that will be written to the slave
- * @count: How many bytes to write, must be less than 64k since msg.len is u16
- *
- * Returns negative errno, or else the number of bytes written.
- */
-int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
-{
- int ret;
- struct i2c_adapter *adap = client->adapter;
- struct i2c_msg msg;
-
- msg.addr = client->addr;
- msg.flags = client->flags & I2C_M_TEN;
- msg.len = count;
- msg.buf = (char *)buf;
-
- ret = i2c_transfer(adap, &msg, 1);
-
- /*
- * If everything went ok (i.e. 1 msg transmitted), return #bytes
- * transmitted, else error code.
- */
- return (ret == 1) ? count : ret;
-}
-EXPORT_SYMBOL(i2c_master_send);
-
-/**
- * i2c_master_recv - issue a single I2C message in master receive mode
+ * i2c_transfer_buffer_flags - issue a single I2C message transferring data
+ * to/from a buffer
* @client: Handle to slave device
- * @buf: Where to store data read from slave
- * @count: How many bytes to read, must be less than 64k since msg.len is u16
+ * @buf: Where the data is stored
+ * @count: How many bytes to transfer, must be less than 64k since msg.len is u16
+ * @flags: The flags to be used for the message, e.g. I2C_M_RD for reads
*
- * Returns negative errno, or else the number of bytes read.
+ * Returns negative errno, or else the number of bytes transferred.
*/
-int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
+int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf,
+ int count, u16 flags)
{
- struct i2c_adapter *adap = client->adapter;
- struct i2c_msg msg;
int ret;
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = flags | (client->flags & I2C_M_TEN),
+ .len = count,
+ .buf = buf,
+ };
- msg.addr = client->addr;
- msg.flags = client->flags & I2C_M_TEN;
- msg.flags |= I2C_M_RD;
- msg.len = count;
- msg.buf = buf;
-
- ret = i2c_transfer(adap, &msg, 1);
+ ret = i2c_transfer(client->adapter, &msg, 1);
/*
- * If everything went ok (i.e. 1 msg received), return #bytes received,
- * else error code.
+ * If everything went ok (i.e. 1 msg transferred), return #bytes
+ * transferred, else error code.
*/
return (ret == 1) ? count : ret;
}
-EXPORT_SYMBOL(i2c_master_recv);
+EXPORT_SYMBOL(i2c_transfer_buffer_flags);
/* ----------------------------------------------------
* the i2c address scanning function
@@ -2265,6 +2199,52 @@ void i2c_put_adapter(struct i2c_adapter *adap)
}
EXPORT_SYMBOL(i2c_put_adapter);
+/**
+ * i2c_get_dma_safe_msg_buf() - get a DMA safe buffer for the given i2c_msg
+ * @msg: the message to be checked
+ * @threshold: the minimum number of bytes for which using DMA makes sense
+ *
+ * Return: NULL if a DMA safe buffer was not obtained. Use msg->buf with PIO.
+ * Or a valid pointer to be used with DMA. After use, release it by
+ * calling i2c_release_dma_safe_msg_buf().
+ *
+ * This function must only be called from process context!
+ */
+u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold)
+{
+ if (msg->len < threshold)
+ return NULL;
+
+ if (msg->flags & I2C_M_DMA_SAFE)
+ return msg->buf;
+
+ pr_debug("using bounce buffer for addr=0x%02x, len=%d\n",
+ msg->addr, msg->len);
+
+ if (msg->flags & I2C_M_RD)
+ return kzalloc(msg->len, GFP_KERNEL);
+ else
+ return kmemdup(msg->buf, msg->len, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf);
+
+/**
+ * i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
+ * @msg: the message to be synced with
+ * @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL.
+ */
+void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf)
+{
+ if (!buf || buf == msg->buf)
+ return;
+
+ if (msg->flags & I2C_M_RD)
+ memcpy(msg->buf, buf, msg->len);
+
+ kfree(buf);
+}
+EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf);
+
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
index a1082c04ac5c..59d5cf376f6a 100644
--- a/drivers/i2c/i2c-core-smbus.c
+++ b/drivers/i2c/i2c-core-smbus.c
@@ -18,6 +18,7 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/i2c-smbus.h>
+#include <linux/slab.h>
#define CREATE_TRACE_POINTS
#include <trace/events/smbus.h>
@@ -291,6 +292,22 @@ s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command,
}
EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
+static void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val)
+{
+ bool is_read = msg->flags & I2C_M_RD;
+ unsigned char *dma_buf;
+
+ dma_buf = kzalloc(I2C_SMBUS_BLOCK_MAX + (is_read ? 2 : 3), GFP_KERNEL);
+ if (!dma_buf)
+ return;
+
+ msg->buf = dma_buf;
+ msg->flags |= I2C_M_DMA_SAFE;
+
+ if (init_val)
+ msg->buf[0] = init_val;
+}
+
/* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
@@ -368,6 +385,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by
the underlying bus driver */
+ i2c_smbus_try_get_dmabuf(&msg[1], 0);
} else {
msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
@@ -376,8 +394,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
data->block[0]);
return -EINVAL;
}
+
+ i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++)
- msgbuf0[i] = data->block[i-1];
+ msg[0].buf[i] = data->block[i - 1];
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
@@ -389,12 +409,16 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
data->block[0]);
return -EINVAL;
}
+
msg[0].len = data->block[0] + 2;
+ i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++)
- msgbuf0[i] = data->block[i-1];
+ msg[0].buf[i] = data->block[i - 1];
+
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by
the underlying bus driver */
+ i2c_smbus_try_get_dmabuf(&msg[1], 0);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
@@ -406,10 +430,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
if (read_write == I2C_SMBUS_READ) {
msg[1].len = data->block[0];
+ i2c_smbus_try_get_dmabuf(&msg[1], 0);
} else {
msg[0].len = data->block[0] + 1;
+
+ i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i <= data->block[0]; i++)
- msgbuf0[i] = data->block[i];
+ msg[0].buf[i] = data->block[i];
}
break;
default:
@@ -457,14 +484,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < data->block[0]; i++)
- data->block[i+1] = msgbuf1[i];
+ data->block[i + 1] = msg[1].buf[i];
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
- for (i = 0; i < msgbuf1[0] + 1; i++)
- data->block[i] = msgbuf1[i];
+ for (i = 0; i < msg[1].buf[0] + 1; i++)
+ data->block[i] = msg[1].buf[i];
break;
}
+
+ if (msg[0].flags & I2C_M_DMA_SAFE)
+ kfree(msg[0].buf);
+ if (msg[1].flags & I2C_M_DMA_SAFE)
+ kfree(msg[1].buf);
+
return 0;
}
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 2cab27a68479..036a03f0d0a6 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -264,6 +264,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
res = PTR_ERR(msgs[i].buf);
break;
}
+ /* memdup_user allocates with GFP_KERNEL, so DMA is ok */
+ msgs[i].flags |= I2C_M_DMA_SAFE;
/*
* If the message length is received from the slave (similar
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 0f5c8fc36625..52a4a922e7e6 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -64,11 +64,11 @@ config I2C_MUX_PCA9541
will be called i2c-mux-pca9541.
config I2C_MUX_PCA954x
- tristate "Philips PCA954x I2C Mux/switches"
+ tristate "NXP PCA954x and PCA984x I2C Mux/switches"
depends on GPIOLIB || COMPILE_TEST
help
- If you say yes here you get support for the Philips PCA954x
- I2C mux/switch devices.
+ If you say yes here you get support for the NXP PCA954x
+ and PCA984x I2C mux/switch devices.
This driver can also be built as a module. If so, the module
will be called i2c-mux-pca954x.
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 2ca068d8b92d..fbb84c7ef282 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -4,11 +4,11 @@
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
*
- * This module supports the PCA954x series of I2C multiplexer/switch chips
- * made by Philips Semiconductors.
+ * This module supports the PCA954x and PCA954x series of I2C multiplexer/switch
+ * chips made by NXP Semiconductors.
* This includes the:
- * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
- * and PCA9548.
+ * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547,
+ * PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849.
*
* These chips are all controlled via the I2C bus itself, and all have a
* single 8-bit register. The upstream "parent" bus fans out to two,
@@ -63,6 +63,10 @@ enum pca_type {
pca_9546,
pca_9547,
pca_9548,
+ pca_9846,
+ pca_9847,
+ pca_9848,
+ pca_9849,
};
struct chip_desc {
@@ -129,6 +133,24 @@ static const struct chip_desc chips[] = {
.nchans = 8,
.muxtype = pca954x_isswi,
},
+ [pca_9846] = {
+ .nchans = 4,
+ .muxtype = pca954x_isswi,
+ },
+ [pca_9847] = {
+ .nchans = 8,
+ .enable = 0x8,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9848] = {
+ .nchans = 8,
+ .muxtype = pca954x_isswi,
+ },
+ [pca_9849] = {
+ .nchans = 4,
+ .enable = 0x4,
+ .muxtype = pca954x_ismux,
+ },
};
static const struct i2c_device_id pca954x_id[] = {
@@ -140,6 +162,10 @@ static const struct i2c_device_id pca954x_id[] = {
{ "pca9546", pca_9546 },
{ "pca9547", pca_9547 },
{ "pca9548", pca_9548 },
+ { "pca9846", pca_9846 },
+ { "pca9847", pca_9847 },
+ { "pca9848", pca_9848 },
+ { "pca9849", pca_9849 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca954x_id);
@@ -154,6 +180,10 @@ static const struct of_device_id pca954x_of_match[] = {
{ .compatible = "nxp,pca9546", .data = &chips[pca_9546] },
{ .compatible = "nxp,pca9547", .data = &chips[pca_9547] },
{ .compatible = "nxp,pca9548", .data = &chips[pca_9548] },
+ { .compatible = "nxp,pca9846", .data = &chips[pca_9846] },
+ { .compatible = "nxp,pca9847", .data = &chips[pca_9847] },
+ { .compatible = "nxp,pca9848", .data = &chips[pca_9848] },
+ { .compatible = "nxp,pca9849", .data = &chips[pca_9849] },
{}
};
MODULE_DEVICE_TABLE(of, pca954x_of_match);
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index f6c9c3dc6cad..c948e5a4cb04 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -177,6 +177,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
sizeof(mux->data));
} else {
ret = i2c_mux_reg_probe_dt(mux, pdev);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
if (ret < 0) {
dev_err(&pdev->dev, "Error parsing device tree");
return ret;
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index de58762097c4..68a1ac929917 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -4,6 +4,7 @@ config EEPROM_AT24
tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
depends on I2C && SYSFS
select NVMEM
+ select REGMAP_I2C
help
Enable this driver to get read/write support to most I2C EEPROMs
and compatible devices like FRAMs, SRAMs, ROMs etc. After you
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 4d63ac8a82e0..01f9c4921c50 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -24,8 +24,10 @@
#include <linux/acpi.h>
#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>
/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
@@ -55,14 +57,13 @@
* which won't work on pure SMBus systems.
*/
+struct at24_client {
+ struct i2c_client *client;
+ struct regmap *regmap;
+};
+
struct at24_data {
struct at24_platform_data chip;
- int use_smbus;
- int use_smbus_write;
-
- ssize_t (*read_func)(struct at24_data *, char *, unsigned int, size_t);
- ssize_t (*write_func)(struct at24_data *,
- const char *, unsigned int, size_t);
/*
* Lock protects against activities from other Linux tasks,
@@ -70,18 +71,20 @@ struct at24_data {
*/
struct mutex lock;
- u8 *writebuf;
- unsigned write_max;
- unsigned num_addresses;
+ unsigned int write_max;
+ unsigned int num_addresses;
+ unsigned int offset_adj;
struct nvmem_config nvmem_config;
struct nvmem_device *nvmem;
+ struct gpio_desc *wp_gpio;
+
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us, and we'll use them with SMBus calls.
*/
- struct i2c_client *client[];
+ struct at24_client client[];
};
/*
@@ -93,27 +96,17 @@ struct at24_data {
*
* This value is forced to be a power of two so that writes align on pages.
*/
-static unsigned io_limit = 128;
-module_param(io_limit, uint, 0);
-MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)");
+static unsigned int at24_io_limit = 128;
+module_param_named(io_limit, at24_io_limit, uint, 0);
+MODULE_PARM_DESC(at24_io_limit, "Maximum bytes per I/O (default 128)");
/*
* Specs often allow 5 msec for a page write, sometimes 20 msec;
* it's important to recover from write timeouts.
*/
-static unsigned write_timeout = 25;
-module_param(write_timeout, uint, 0);
-MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
-
-#define AT24_SIZE_BYTELEN 5
-#define AT24_SIZE_FLAGS 8
-
-#define AT24_BITMASK(x) (BIT(x) - 1)
-
-/* create non-zero magic value for given eeprom parameters */
-#define AT24_DEVICE_MAGIC(_len, _flags) \
- ((1 << AT24_SIZE_FLAGS | (_flags)) \
- << AT24_SIZE_BYTELEN | ilog2(_len))
+static unsigned int at24_write_timeout = 25;
+module_param_named(write_timeout, at24_write_timeout, uint, 0);
+MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
/*
* Both reads and writes fail if the previous write didn't complete yet. This
@@ -126,118 +119,123 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
* iteration of processing the request. Both should be unsigned integers
* holding at least 32 bits.
*/
-#define loop_until_timeout(tout, op_time) \
- for (tout = jiffies + msecs_to_jiffies(write_timeout), op_time = 0; \
+#define at24_loop_until_timeout(tout, op_time) \
+ for (tout = jiffies + msecs_to_jiffies(at24_write_timeout), \
+ op_time = 0; \
op_time ? time_before(op_time, tout) : true; \
usleep_range(1000, 1500), op_time = jiffies)
+struct at24_chip_data {
+ /*
+ * these fields mirror their equivalents in
+ * struct at24_platform_data
+ */
+ u32 byte_len;
+ u8 flags;
+};
+
+#define AT24_CHIP_DATA(_name, _len, _flags) \
+ static const struct at24_chip_data _name = { \
+ .byte_len = _len, .flags = _flags, \
+ }
+
+/* needs 8 addresses as A0-A2 are ignored */
+AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR);
+/* old variants can't be handled with this generic entry! */
+AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0);
+AT24_CHIP_DATA(at24_data_24cs01, 16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
+AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, 0);
+AT24_CHIP_DATA(at24_data_24cs02, 16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
+AT24_CHIP_DATA(at24_data_24mac402, 48 / 8,
+ AT24_FLAG_MAC | AT24_FLAG_READONLY);
+AT24_CHIP_DATA(at24_data_24mac602, 64 / 8,
+ AT24_FLAG_MAC | AT24_FLAG_READONLY);
+/* spd is a 24c02 in memory DIMMs */
+AT24_CHIP_DATA(at24_data_spd, 2048 / 8,
+ AT24_FLAG_READONLY | AT24_FLAG_IRUGO);
+AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0);
+AT24_CHIP_DATA(at24_data_24cs04, 16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
+/* 24rf08 quirk is handled at i2c-core */
+AT24_CHIP_DATA(at24_data_24c08, 8192 / 8, 0);
+AT24_CHIP_DATA(at24_data_24cs08, 16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
+AT24_CHIP_DATA(at24_data_24c16, 16384 / 8, 0);
+AT24_CHIP_DATA(at24_data_24cs16, 16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
+AT24_CHIP_DATA(at24_data_24c32, 32768 / 8, AT24_FLAG_ADDR16);
+AT24_CHIP_DATA(at24_data_24cs32, 16,
+ AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
+AT24_CHIP_DATA(at24_data_24c64, 65536 / 8, AT24_FLAG_ADDR16);
+AT24_CHIP_DATA(at24_data_24cs64, 16,
+ AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
+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);
+/* identical to 24c08 ? */
+AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
+
static const struct i2c_device_id at24_ids[] = {
- /* needs 8 addresses as A0-A2 are ignored */
- { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
- /* old variants can't be handled with this generic entry! */
- { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
- { "24cs01", AT24_DEVICE_MAGIC(16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
- { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
- { "24cs02", AT24_DEVICE_MAGIC(16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
- { "24mac402", AT24_DEVICE_MAGIC(48 / 8,
- AT24_FLAG_MAC | AT24_FLAG_READONLY) },
- { "24mac602", AT24_DEVICE_MAGIC(64 / 8,
- AT24_FLAG_MAC | AT24_FLAG_READONLY) },
- /* spd is a 24c02 in memory DIMMs */
- { "spd", AT24_DEVICE_MAGIC(2048 / 8,
- AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
- { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
- { "24cs04", AT24_DEVICE_MAGIC(16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
- /* 24rf08 quirk is handled at i2c-core */
- { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
- { "24cs08", AT24_DEVICE_MAGIC(16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
- { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
- { "24cs16", AT24_DEVICE_MAGIC(16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
- { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
- { "24cs32", AT24_DEVICE_MAGIC(16,
- AT24_FLAG_ADDR16 |
- AT24_FLAG_SERIAL |
- AT24_FLAG_READONLY) },
- { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
- { "24cs64", AT24_DEVICE_MAGIC(16,
- AT24_FLAG_ADDR16 |
- AT24_FLAG_SERIAL |
- AT24_FLAG_READONLY) },
- { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
- { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
- { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
- { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
- { "at24", 0 },
+ { "24c00", (kernel_ulong_t)&at24_data_24c00 },
+ { "24c01", (kernel_ulong_t)&at24_data_24c01 },
+ { "24cs01", (kernel_ulong_t)&at24_data_24cs01 },
+ { "24c02", (kernel_ulong_t)&at24_data_24c02 },
+ { "24cs02", (kernel_ulong_t)&at24_data_24cs02 },
+ { "24mac402", (kernel_ulong_t)&at24_data_24mac402 },
+ { "24mac602", (kernel_ulong_t)&at24_data_24mac602 },
+ { "spd", (kernel_ulong_t)&at24_data_spd },
+ { "24c04", (kernel_ulong_t)&at24_data_24c04 },
+ { "24cs04", (kernel_ulong_t)&at24_data_24cs04 },
+ { "24c08", (kernel_ulong_t)&at24_data_24c08 },
+ { "24cs08", (kernel_ulong_t)&at24_data_24cs08 },
+ { "24c16", (kernel_ulong_t)&at24_data_24c16 },
+ { "24cs16", (kernel_ulong_t)&at24_data_24cs16 },
+ { "24c32", (kernel_ulong_t)&at24_data_24c32 },
+ { "24cs32", (kernel_ulong_t)&at24_data_24cs32 },
+ { "24c64", (kernel_ulong_t)&at24_data_24c64 },
+ { "24cs64", (kernel_ulong_t)&at24_data_24cs64 },
+ { "24c128", (kernel_ulong_t)&at24_data_24c128 },
+ { "24c256", (kernel_ulong_t)&at24_data_24c256 },
+ { "24c512", (kernel_ulong_t)&at24_data_24c512 },
+ { "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
+ { "at24", 0 },
{ /* END OF LIST */ }
};
MODULE_DEVICE_TABLE(i2c, at24_ids);
static const struct of_device_id at24_of_match[] = {
- {
- .compatible = "atmel,24c00",
- .data = (void *)AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR)
- },
- {
- .compatible = "atmel,24c01",
- .data = (void *)AT24_DEVICE_MAGIC(1024 / 8, 0)
- },
- {
- .compatible = "atmel,24c02",
- .data = (void *)AT24_DEVICE_MAGIC(2048 / 8, 0)
- },
- {
- .compatible = "atmel,spd",
- .data = (void *)AT24_DEVICE_MAGIC(2048 / 8,
- AT24_FLAG_READONLY | AT24_FLAG_IRUGO)
- },
- {
- .compatible = "atmel,24c04",
- .data = (void *)AT24_DEVICE_MAGIC(4096 / 8, 0)
- },
- {
- .compatible = "atmel,24c08",
- .data = (void *)AT24_DEVICE_MAGIC(8192 / 8, 0)
- },
- {
- .compatible = "atmel,24c16",
- .data = (void *)AT24_DEVICE_MAGIC(16384 / 8, 0)
- },
- {
- .compatible = "atmel,24c32",
- .data = (void *)AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16)
- },
- {
- .compatible = "atmel,24c64",
- .data = (void *)AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16)
- },
- {
- .compatible = "atmel,24c128",
- .data = (void *)AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16)
- },
- {
- .compatible = "atmel,24c256",
- .data = (void *)AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16)
- },
- {
- .compatible = "atmel,24c512",
- .data = (void *)AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16)
- },
- {
- .compatible = "atmel,24c1024",
- .data = (void *)AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16)
- },
- { },
+ { .compatible = "atmel,24c00", .data = &at24_data_24c00 },
+ { .compatible = "atmel,24c01", .data = &at24_data_24c01 },
+ { .compatible = "atmel,24cs01", .data = &at24_data_24cs01 },
+ { .compatible = "atmel,24c02", .data = &at24_data_24c02 },
+ { .compatible = "atmel,24cs02", .data = &at24_data_24cs02 },
+ { .compatible = "atmel,24mac402", .data = &at24_data_24mac402 },
+ { .compatible = "atmel,24mac602", .data = &at24_data_24mac602 },
+ { .compatible = "atmel,spd", .data = &at24_data_spd },
+ { .compatible = "atmel,24c04", .data = &at24_data_24c04 },
+ { .compatible = "atmel,24cs04", .data = &at24_data_24cs04 },
+ { .compatible = "atmel,24c08", .data = &at24_data_24c08 },
+ { .compatible = "atmel,24cs08", .data = &at24_data_24cs08 },
+ { .compatible = "atmel,24c16", .data = &at24_data_24c16 },
+ { .compatible = "atmel,24cs16", .data = &at24_data_24cs16 },
+ { .compatible = "atmel,24c32", .data = &at24_data_24c32 },
+ { .compatible = "atmel,24cs32", .data = &at24_data_24cs32 },
+ { .compatible = "atmel,24c64", .data = &at24_data_24c64 },
+ { .compatible = "atmel,24cs64", .data = &at24_data_24cs64 },
+ { .compatible = "atmel,24c128", .data = &at24_data_24c128 },
+ { .compatible = "atmel,24c256", .data = &at24_data_24c256 },
+ { .compatible = "atmel,24c512", .data = &at24_data_24c512 },
+ { .compatible = "atmel,24c1024", .data = &at24_data_24c1024 },
+ { /* END OF LIST */ },
};
MODULE_DEVICE_TABLE(of, at24_of_match);
static const struct acpi_device_id at24_acpi_ids[] = {
- { "INT3499", AT24_DEVICE_MAGIC(8192 / 8, 0) },
- { }
+ { "INT3499", (kernel_ulong_t)&at24_data_INT3499 },
+ { /* END OF LIST */ }
};
MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
@@ -251,20 +249,11 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
* Slave address and byte offset derive from the offset. Always
* set the byte address; on a multi-master board, another master
* may have changed the chip's "current" address pointer.
- *
- * REVISIT some multi-address chips don't rollover page reads to
- * the next slave address, so we may need to truncate the count.
- * Those chips might need another quirk flag.
- *
- * If the real hardware used four adjacent 24c02 chips and that
- * were misconfigured as one 24c08, that would be a similar effect:
- * one "eeprom" file not four, but larger reads would fail when
- * they crossed certain pages.
*/
-static struct i2c_client *at24_translate_offset(struct at24_data *at24,
- unsigned int *offset)
+static struct at24_client *at24_translate_offset(struct at24_data *at24,
+ unsigned int *offset)
{
- unsigned i;
+ unsigned int i;
if (at24->chip.flags & AT24_FLAG_ADDR16) {
i = *offset >> 16;
@@ -274,168 +263,55 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24,
*offset &= 0xff;
}
- return at24->client[i];
+ return &at24->client[i];
}
-static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
+static size_t at24_adjust_read_count(struct at24_data *at24,
unsigned int offset, size_t count)
{
- unsigned long timeout, read_time;
- struct i2c_client *client;
- int status;
-
- client = at24_translate_offset(at24, &offset);
-
- if (count > io_limit)
- count = io_limit;
-
- /* Smaller eeproms can work given some SMBus extension calls */
- if (count > I2C_SMBUS_BLOCK_MAX)
- count = I2C_SMBUS_BLOCK_MAX;
-
- loop_until_timeout(timeout, read_time) {
- status = i2c_smbus_read_i2c_block_data_or_emulated(client,
- offset,
- count, buf);
-
- dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
- count, offset, status, jiffies);
-
- if (status == count)
- return count;
- }
-
- return -ETIMEDOUT;
-}
-
-static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
- unsigned int offset, size_t count)
-{
- unsigned long timeout, read_time;
- struct i2c_client *client;
- struct i2c_msg msg[2];
- int status, i;
- u8 msgbuf[2];
-
- memset(msg, 0, sizeof(msg));
- client = at24_translate_offset(at24, &offset);
-
- if (count > io_limit)
- count = io_limit;
+ unsigned int bits;
+ size_t remainder;
/*
- * When we have a better choice than SMBus calls, use a combined I2C
- * message. Write address; then read up to io_limit data bytes. Note
- * that read page rollover helps us here (unlike writes). msgbuf is
- * u8 and will cast to our needs.
+ * In case of multi-address chips that don't rollover reads to
+ * the next slave address: truncate the count to the slave boundary,
+ * so that the read never straddles slaves.
*/
- i = 0;
- if (at24->chip.flags & AT24_FLAG_ADDR16)
- msgbuf[i++] = offset >> 8;
- msgbuf[i++] = offset;
-
- msg[0].addr = client->addr;
- msg[0].buf = msgbuf;
- msg[0].len = i;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].buf = buf;
- msg[1].len = count;
-
- loop_until_timeout(timeout, read_time) {
- status = i2c_transfer(client->adapter, msg, 2);
- if (status == 2)
- status = count;
-
- dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
- count, offset, status, jiffies);
-
- if (status == count)
- return count;
+ if (at24->chip.flags & AT24_FLAG_NO_RDROL) {
+ bits = (at24->chip.flags & AT24_FLAG_ADDR16) ? 16 : 8;
+ remainder = BIT(bits) - offset;
+ if (count > remainder)
+ count = remainder;
}
- return -ETIMEDOUT;
+ if (count > at24_io_limit)
+ count = at24_io_limit;
+
+ return count;
}
-static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf,
- unsigned int offset, size_t count)
+static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
+ unsigned int offset, size_t count)
{
unsigned long timeout, read_time;
+ struct at24_client *at24_client;
struct i2c_client *client;
- struct i2c_msg msg[2];
- u8 addrbuf[2];
- int status;
-
- client = at24_translate_offset(at24, &offset);
-
- memset(msg, 0, sizeof(msg));
- msg[0].addr = client->addr;
- msg[0].buf = addrbuf;
-
- /*
- * The address pointer of the device is shared between the regular
- * EEPROM array and the serial number block. The dummy write (part of
- * the sequential read protocol) ensures the address pointer is reset
- * to the desired position.
- */
- if (at24->chip.flags & AT24_FLAG_ADDR16) {
- /*
- * For 16 bit address pointers, the word address must contain
- * a '10' sequence in bits 11 and 10 regardless of the
- * intended position of the address pointer.
- */
- addrbuf[0] = 0x08;
- addrbuf[1] = offset;
- msg[0].len = 2;
- } else {
- /*
- * Otherwise the word address must begin with a '10' sequence,
- * regardless of the intended address.
- */
- addrbuf[0] = 0x80 + offset;
- msg[0].len = 1;
- }
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].buf = buf;
- msg[1].len = count;
+ struct regmap *regmap;
+ int ret;
- loop_until_timeout(timeout, read_time) {
- status = i2c_transfer(client->adapter, msg, 2);
- if (status == 2)
- return count;
- }
+ at24_client = at24_translate_offset(at24, &offset);
+ regmap = at24_client->regmap;
+ client = at24_client->client;
+ count = at24_adjust_read_count(at24, offset, count);
- return -ETIMEDOUT;
-}
+ /* adjust offset for mac and serial read ops */
+ offset += at24->offset_adj;
-static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf,
- unsigned int offset, size_t count)
-{
- unsigned long timeout, read_time;
- struct i2c_client *client;
- struct i2c_msg msg[2];
- u8 addrbuf[2];
- int status;
-
- client = at24_translate_offset(at24, &offset);
-
- memset(msg, 0, sizeof(msg));
- msg[0].addr = client->addr;
- msg[0].buf = addrbuf;
- /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */
- addrbuf[0] = 0xa0 - at24->chip.byte_len + offset;
- msg[0].len = 1;
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].buf = buf;
- msg[1].len = count;
-
- loop_until_timeout(timeout, read_time) {
- status = i2c_transfer(client->adapter, msg, 2);
- if (status == 2)
+ at24_loop_until_timeout(timeout, read_time) {
+ ret = regmap_bulk_read(regmap, offset, buf, count);
+ dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
+ count, offset, ret, jiffies);
+ if (!ret)
return count;
}
@@ -454,7 +330,7 @@ static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf,
static size_t at24_adjust_write_count(struct at24_data *at24,
unsigned int offset, size_t count)
{
- unsigned next_page;
+ unsigned int next_page;
/* write_max is at most a page */
if (count > at24->write_max)
@@ -468,91 +344,25 @@ static size_t at24_adjust_write_count(struct at24_data *at24,
return count;
}
-static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24,
- const char *buf,
- unsigned int offset, size_t count)
+static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
+ unsigned int offset, size_t count)
{
unsigned long timeout, write_time;
+ struct at24_client *at24_client;
struct i2c_client *client;
- ssize_t status = 0;
-
- client = at24_translate_offset(at24, &offset);
- count = at24_adjust_write_count(at24, offset, count);
-
- loop_until_timeout(timeout, write_time) {
- status = i2c_smbus_write_i2c_block_data(client,
- offset, count, buf);
- if (status == 0)
- status = count;
-
- dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
- count, offset, status, jiffies);
-
- if (status == count)
- return count;
- }
-
- return -ETIMEDOUT;
-}
-
-static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24,
- const char *buf,
- unsigned int offset, size_t count)
-{
- unsigned long timeout, write_time;
- struct i2c_client *client;
- ssize_t status = 0;
-
- client = at24_translate_offset(at24, &offset);
-
- loop_until_timeout(timeout, write_time) {
- status = i2c_smbus_write_byte_data(client, offset, buf[0]);
- if (status == 0)
- status = count;
-
- dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
- count, offset, status, jiffies);
-
- if (status == count)
- return count;
- }
-
- return -ETIMEDOUT;
-}
-
-static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
- unsigned int offset, size_t count)
-{
- unsigned long timeout, write_time;
- struct i2c_client *client;
- struct i2c_msg msg;
- ssize_t status = 0;
- int i = 0;
+ struct regmap *regmap;
+ int ret;
- client = at24_translate_offset(at24, &offset);
+ at24_client = at24_translate_offset(at24, &offset);
+ regmap = at24_client->regmap;
+ client = at24_client->client;
count = at24_adjust_write_count(at24, offset, count);
- msg.addr = client->addr;
- msg.flags = 0;
-
- /* msg.buf is u8 and casts will mask the values */
- msg.buf = at24->writebuf;
- if (at24->chip.flags & AT24_FLAG_ADDR16)
- msg.buf[i++] = offset >> 8;
-
- msg.buf[i++] = offset;
- memcpy(&msg.buf[i], buf, count);
- msg.len = i + count;
-
- loop_until_timeout(timeout, write_time) {
- status = i2c_transfer(client->adapter, &msg, 1);
- if (status == 1)
- status = count;
-
- dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
- count, offset, status, jiffies);
-
- if (status == count)
+ at24_loop_until_timeout(timeout, write_time) {
+ ret = regmap_bulk_write(regmap, offset, buf, count);
+ dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n",
+ count, offset, ret, jiffies);
+ if (!ret)
return count;
}
@@ -562,7 +372,7 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
static int at24_read(void *priv, unsigned int off, void *val, size_t count)
{
struct at24_data *at24 = priv;
- struct device *dev = &at24->client[0]->dev;
+ struct device *dev = &at24->client[0].client->dev;
char *buf = val;
int ret;
@@ -587,7 +397,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
while (count) {
int status;
- status = at24->read_func(at24, buf, off, count);
+ status = at24_regmap_read(at24, buf, off, count);
if (status < 0) {
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
@@ -608,7 +418,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{
struct at24_data *at24 = priv;
- struct device *dev = &at24->client[0]->dev;
+ struct device *dev = &at24->client[0].client->dev;
char *buf = val;
int ret;
@@ -629,12 +439,14 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
* from this host, but not from other I2C masters.
*/
mutex_lock(&at24->lock);
+ gpiod_set_value_cansleep(at24->wp_gpio, 0);
while (count) {
int status;
- status = at24->write_func(at24, buf, off, count);
+ status = at24_regmap_write(at24, buf, off, count);
if (status < 0) {
+ gpiod_set_value_cansleep(at24->wp_gpio, 1);
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
return status;
@@ -644,6 +456,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
count -= status;
}
+ gpiod_set_value_cansleep(at24->wp_gpio, 1);
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
@@ -658,6 +471,8 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
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, "size", &val);
if (!err)
@@ -676,16 +491,38 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
}
}
+static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len)
+{
+ if (flags & AT24_FLAG_MAC) {
+ /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */
+ return 0xa0 - byte_len;
+ } else if (flags & AT24_FLAG_SERIAL && flags & AT24_FLAG_ADDR16) {
+ /*
+ * For 16 bit address pointers, the word address must contain
+ * a '10' sequence in bits 11 and 10 regardless of the
+ * intended position of the address pointer.
+ */
+ return 0x0800;
+ } else if (flags & AT24_FLAG_SERIAL) {
+ /*
+ * Otherwise the word address must begin with a '10' sequence,
+ * regardless of the intended address.
+ */
+ return 0x0080;
+ } else {
+ return 0;
+ }
+}
+
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- struct at24_platform_data chip;
- kernel_ulong_t magic = 0;
+ struct at24_platform_data chip = { 0 };
+ const struct at24_chip_data *cd = NULL;
bool writable;
- int use_smbus = 0;
- int use_smbus_write = 0;
struct at24_data *at24;
int err;
- unsigned i, num_addresses;
+ unsigned int i, num_addresses;
+ struct regmap_config regmap_config = { };
u8 test_byte;
if (client->dev.platform_data) {
@@ -698,28 +535,22 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
if (client->dev.of_node &&
of_match_device(at24_of_match, &client->dev)) {
- magic = (kernel_ulong_t)
- of_device_get_match_data(&client->dev);
+ cd = of_device_get_match_data(&client->dev);
} else if (id) {
- magic = id->driver_data;
+ cd = (void *)id->driver_data;
} else {
const struct acpi_device_id *aid;
aid = acpi_match_device(at24_acpi_ids, &client->dev);
if (aid)
- magic = aid->driver_data;
+ cd = (void *)aid->driver_data;
}
- if (!magic)
+ if (!cd)
return -ENODEV;
- chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
- magic >>= AT24_SIZE_BYTELEN;
- chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
-
+ chip.byte_len = cd->byte_len;
+ chip.flags = cd->flags;
at24_get_pdata(&client->dev, &chip);
-
- chip.setup = NULL;
- chip.context = NULL;
}
if (!is_power_of_2(chip.byte_len))
@@ -733,43 +564,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_warn(&client->dev,
"page_size looks suspicious (no power of 2)!\n");
- /*
- * REVISIT: the size of the EUI-48 byte array is 6 in at24mac402, while
- * the call to ilog2() in AT24_DEVICE_MAGIC() rounds it down to 4.
- *
- * Eventually we'll get rid of the magic values altoghether in favor of
- * real structs, but for now just manually set the right size.
- */
- if (chip.flags & AT24_FLAG_MAC && chip.byte_len == 4)
- chip.byte_len = 6;
-
- /* Use I2C operations unless we're stuck with SMBus extensions. */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- if (chip.flags & AT24_FLAG_ADDR16)
- return -EPFNOSUPPORT;
-
- if (i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
- use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
- } else if (i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_WORD_DATA)) {
- use_smbus = I2C_SMBUS_WORD_DATA;
- } else if (i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
- use_smbus = I2C_SMBUS_BYTE_DATA;
- } else {
- return -EPFNOSUPPORT;
- }
-
- if (i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
- use_smbus_write = I2C_SMBUS_I2C_BLOCK_DATA;
- } else if (i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
- use_smbus_write = I2C_SMBUS_BYTE_DATA;
- chip.page_size = 1;
- }
- }
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
+ !i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
+ chip.page_size = 1;
if (chip.flags & AT24_FLAG_TAKE8ADDR)
num_addresses = 8;
@@ -777,16 +575,28 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
num_addresses = DIV_ROUND_UP(chip.byte_len,
(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
+ regmap_config.val_bits = 8;
+ regmap_config.reg_bits = (chip.flags & AT24_FLAG_ADDR16) ? 16 : 8;
+
at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) +
- num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
+ num_addresses * sizeof(struct at24_client), GFP_KERNEL);
if (!at24)
return -ENOMEM;
mutex_init(&at24->lock);
- at24->use_smbus = use_smbus;
- at24->use_smbus_write = use_smbus_write;
at24->chip = chip;
at24->num_addresses = num_addresses;
+ at24->offset_adj = at24_get_offset_adj(chip.flags, chip.byte_len);
+
+ at24->wp_gpio = devm_gpiod_get_optional(&client->dev,
+ "wp", GPIOD_OUT_HIGH);
+ if (IS_ERR(at24->wp_gpio))
+ return PTR_ERR(at24->wp_gpio);
+
+ at24->client[0].client = client;
+ at24->client[0].regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(at24->client[0].regmap))
+ return PTR_ERR(at24->client[0].regmap);
if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) {
dev_err(&client->dev,
@@ -794,59 +604,32 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -EINVAL;
}
- if (chip.flags & AT24_FLAG_SERIAL) {
- at24->read_func = at24_eeprom_read_serial;
- } else if (chip.flags & AT24_FLAG_MAC) {
- at24->read_func = at24_eeprom_read_mac;
- } else {
- at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
- : at24_eeprom_read_i2c;
- }
-
- if (at24->use_smbus) {
- if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA)
- at24->write_func = at24_eeprom_write_smbus_block;
- else
- at24->write_func = at24_eeprom_write_smbus_byte;
- } else {
- at24->write_func = at24_eeprom_write_i2c;
- }
-
writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) {
- if (!use_smbus || use_smbus_write) {
-
- unsigned write_max = chip.page_size;
-
- if (write_max > io_limit)
- write_max = io_limit;
- if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
- write_max = I2C_SMBUS_BLOCK_MAX;
- at24->write_max = write_max;
-
- /* buffer (data + address at the beginning) */
- at24->writebuf = devm_kzalloc(&client->dev,
- write_max + 2, GFP_KERNEL);
- if (!at24->writebuf)
- return -ENOMEM;
- } else {
- dev_warn(&client->dev,
- "cannot write due to controller restrictions.");
- }
+ at24->write_max = min_t(unsigned int,
+ chip.page_size, at24_io_limit);
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
+ at24->write_max > I2C_SMBUS_BLOCK_MAX)
+ at24->write_max = I2C_SMBUS_BLOCK_MAX;
}
- at24->client[0] = client;
-
/* use dummy devices for multiple-address chips */
for (i = 1; i < num_addresses; i++) {
- at24->client[i] = i2c_new_dummy(client->adapter,
- client->addr + i);
- if (!at24->client[i]) {
+ at24->client[i].client = i2c_new_dummy(client->adapter,
+ client->addr + i);
+ if (!at24->client[i].client) {
dev_err(&client->dev, "address 0x%02x unavailable\n",
client->addr + i);
err = -EADDRINUSE;
goto err_clients;
}
+ at24->client[i].regmap = devm_regmap_init_i2c(
+ at24->client[i].client,
+ &regmap_config);
+ if (IS_ERR(at24->client[i].regmap)) {
+ err = PTR_ERR(at24->client[i].regmap);
+ goto err_clients;
+ }
}
i2c_set_clientdata(client, at24);
@@ -890,12 +673,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
chip.byte_len, client->name,
writable ? "writable" : "read-only", at24->write_max);
- if (use_smbus == I2C_SMBUS_WORD_DATA ||
- use_smbus == I2C_SMBUS_BYTE_DATA) {
- dev_notice(&client->dev, "Falling back to %s reads, "
- "performance will suffer\n", use_smbus ==
- I2C_SMBUS_WORD_DATA ? "word" : "byte");
- }
/* export data to kernel code */
if (chip.setup)
@@ -905,8 +682,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
err_clients:
for (i = 1; i < num_addresses; i++)
- if (at24->client[i])
- i2c_unregister_device(at24->client[i]);
+ if (at24->client[i].client)
+ i2c_unregister_device(at24->client[i].client);
pm_runtime_disable(&client->dev);
@@ -923,7 +700,7 @@ static int at24_remove(struct i2c_client *client)
nvmem_unregister(at24->nvmem);
for (i = 1; i < at24->num_addresses; i++)
- i2c_unregister_device(at24->client[i]);
+ i2c_unregister_device(at24->client[i].client);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
@@ -946,12 +723,12 @@ static struct i2c_driver at24_driver = {
static int __init at24_init(void)
{
- if (!io_limit) {
- pr_err("at24: io_limit must not be 0!\n");
+ if (!at24_io_limit) {
+ pr_err("at24: at24_io_limit must not be 0!\n");
return -EINVAL;
}
- io_limit = rounddown_pow_of_two(io_limit);
+ at24_io_limit = rounddown_pow_of_two(at24_io_limit);
return i2c_add_driver(&at24_driver);
}
module_init(at24_init);
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 0f774406fad0..419a38e7c315 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -55,7 +55,7 @@ typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);
struct module;
struct property_entry;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
/*
* The master routines are the ones normally used to transmit data to devices
* on a bus (or read from them). Apart from two basic transfer functions to
@@ -63,10 +63,68 @@ struct property_entry;
* transmit an arbitrary number of messages without interruption.
* @count must be be less than 64k since msg.len is u16.
*/
-extern int i2c_master_send(const struct i2c_client *client, const char *buf,
- int count);
-extern int i2c_master_recv(const struct i2c_client *client, char *buf,
- int count);
+extern int i2c_transfer_buffer_flags(const struct i2c_client *client,
+ char *buf, int count, u16 flags);
+
+/**
+ * i2c_master_recv - issue a single I2C message in master receive mode
+ * @client: Handle to slave device
+ * @buf: Where to store data read from slave
+ * @count: How many bytes to read, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes read.
+ */
+static inline int i2c_master_recv(const struct i2c_client *client,
+ char *buf, int count)
+{
+ return i2c_transfer_buffer_flags(client, buf, count, I2C_M_RD);
+};
+
+/**
+ * i2c_master_recv_dmasafe - issue a single I2C message in master receive mode
+ * using a DMA safe buffer
+ * @client: Handle to slave device
+ * @buf: Where to store data read from slave, must be safe to use with DMA
+ * @count: How many bytes to read, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes read.
+ */
+static inline int i2c_master_recv_dmasafe(const struct i2c_client *client,
+ char *buf, int count)
+{
+ return i2c_transfer_buffer_flags(client, buf, count,
+ I2C_M_RD | I2C_M_DMA_SAFE);
+};
+
+/**
+ * i2c_master_send - issue a single I2C message in master transmit mode
+ * @client: Handle to slave device
+ * @buf: Data that will be written to the slave
+ * @count: How many bytes to write, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes written.
+ */
+static inline int i2c_master_send(const struct i2c_client *client,
+ const char *buf, int count)
+{
+ return i2c_transfer_buffer_flags(client, (char *)buf, count, 0);
+};
+
+/**
+ * i2c_master_send_dmasafe - issue a single I2C message in master transmit mode
+ * using a DMA safe buffer
+ * @client: Handle to slave device
+ * @buf: Data that will be written to the slave, must be safe to use with DMA
+ * @count: How many bytes to write, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes written.
+ */
+static inline int i2c_master_send_dmasafe(const struct i2c_client *client,
+ const char *buf, int count)
+{
+ return i2c_transfer_buffer_flags(client, (char *)buf, count,
+ I2C_M_DMA_SAFE);
+};
/* Transfer num messages.
*/
@@ -354,7 +412,7 @@ struct i2c_board_info {
.type = dev_type, .addr = (dev_addr)
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
/* Add-on boards should register/unregister their devices; e.g. a board
* with integrated I2C, a config eeprom, sensors, and a codec that's
* used in conjunction with the primary hardware.
@@ -485,40 +543,43 @@ struct i2c_timings {
/**
* struct i2c_bus_recovery_info - I2C bus recovery information
* @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or
- * i2c_generic_scl_recovery() or i2c_generic_gpio_recovery().
+ * i2c_generic_scl_recovery().
* @get_scl: This gets current value of SCL line. Mandatory for generic SCL
- * recovery. Used internally for generic GPIO recovery.
- * @set_scl: This sets/clears SCL line. Mandatory for generic SCL recovery. Used
- * internally for generic GPIO recovery.
+ * recovery. Populated internally for generic GPIO recovery.
+ * @set_scl: This sets/clears the SCL line. Mandatory for generic SCL recovery.
+ * Populated internally for generic GPIO recovery.
* @get_sda: This gets current value of SDA line. Optional for generic SCL
- * recovery. Used internally, if sda_gpio is a valid GPIO, for generic GPIO
- * recovery.
+ * recovery. Populated internally, if sda_gpio is a valid GPIO, for generic
+ * GPIO recovery.
+ * @set_sda: This sets/clears the SDA line. Optional for generic SCL recovery.
+ * Populated internally, if sda_gpio is a valid GPIO, for generic GPIO
+ * recovery.
* @prepare_recovery: This will be called before starting recovery. Platform may
* configure padmux here for SDA/SCL line or something else they want.
* @unprepare_recovery: This will be called after completing recovery. Platform
* may configure padmux here for SDA/SCL line or something else they want.
- * @scl_gpio: gpio number of the SCL line. Only required for GPIO recovery.
- * @sda_gpio: gpio number of the SDA line. Only required for GPIO recovery.
+ * @scl_gpiod: gpiod of the SCL line. Only required for GPIO recovery.
+ * @sda_gpiod: gpiod of the SDA line. Only required for GPIO recovery.
*/
struct i2c_bus_recovery_info {
- int (*recover_bus)(struct i2c_adapter *);
+ int (*recover_bus)(struct i2c_adapter *adap);
- int (*get_scl)(struct i2c_adapter *);
- void (*set_scl)(struct i2c_adapter *, int val);
- int (*get_sda)(struct i2c_adapter *);
+ int (*get_scl)(struct i2c_adapter *adap);
+ void (*set_scl)(struct i2c_adapter *adap, int val);
+ int (*get_sda)(struct i2c_adapter *adap);
+ void (*set_sda)(struct i2c_adapter *adap, int val);
- void (*prepare_recovery)(struct i2c_adapter *);
- void (*unprepare_recovery)(struct i2c_adapter *);
+ void (*prepare_recovery)(struct i2c_adapter *adap);
+ void (*unprepare_recovery)(struct i2c_adapter *adap);
/* gpio recovery */
- int scl_gpio;
- int sda_gpio;
+ struct gpio_desc *scl_gpiod;
+ struct gpio_desc *sda_gpiod;
};
int i2c_recover_bus(struct i2c_adapter *adap);
/* Generic recovery routines */
-int i2c_generic_gpio_recovery(struct i2c_adapter *adap);
int i2c_generic_scl_recovery(struct i2c_adapter *adap);
/**
@@ -706,7 +767,7 @@ i2c_unlock_adapter(struct i2c_adapter *adapter)
/* administration...
*/
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
extern int i2c_add_adapter(struct i2c_adapter *);
extern void i2c_del_adapter(struct i2c_adapter *);
extern int i2c_add_numbered_adapter(struct i2c_adapter *);
@@ -769,6 +830,9 @@ static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0);
}
+u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold);
+void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf);
+
int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr);
/**
* module_i2c_driver() - Helper macro for registering a modular I2C driver
diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h
index 271a4e25af67..63507ff464ee 100644
--- a/include/linux/platform_data/at24.h
+++ b/include/linux/platform_data/at24.h
@@ -50,6 +50,8 @@ struct at24_platform_data {
#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;
diff --git a/include/linux/platform_data/i2c-davinci.h b/include/linux/platform_data/i2c-davinci.h
index 89fd34727a24..98967df07468 100644
--- a/include/linux/platform_data/i2c-davinci.h
+++ b/include/linux/platform_data/i2c-davinci.h
@@ -16,9 +16,8 @@
struct davinci_i2c_platform_data {
unsigned int bus_freq; /* standard bus frequency (kHz) */
unsigned int bus_delay; /* post-transaction delay (usec) */
- unsigned int sda_pin; /* GPIO pin ID to use for SDA */
- unsigned int scl_pin; /* GPIO pin ID to use for SCL */
- bool has_pfunc; /*chip has a ICPFUNC register */
+ bool gpio_recovery; /* Use GPIO recovery method */
+ bool has_pfunc; /* Chip has a ICPFUNC register */
};
/* for board setup code */
diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
index fe648032d6b9..f71a1751cacf 100644
--- a/include/uapi/linux/i2c.h
+++ b/include/uapi/linux/i2c.h
@@ -72,6 +72,9 @@ struct i2c_msg {
#define I2C_M_RD 0x0001 /* read data, from slave to master */
/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
+#define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */
+ /* makes only sense in kernelspace */
+ /* userspace buffers are copied anyway */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */

Privacy Policy