Commit 4141cf67 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 3462ac57 e38c8564
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>;
};
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>;
};
Amlogic Meson I2C controller Amlogic Meson I2C controller
Required properties: 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 - reg: physical address and length of the device registers
- interrupts: a single interrupt specifier - interrupts: a single interrupt specifier
- clocks: clock for the device - clocks: clock for the device
......
...@@ -5,6 +5,7 @@ The MediaTek's I2C controller is used to interface with I2C devices. ...@@ -5,6 +5,7 @@ The MediaTek's I2C controller is used to interface with I2C devices.
Required properties: Required properties:
- compatible: value should be either of the following. - compatible: value should be either of the following.
"mediatek,mt2701-i2c", "mediatek,mt6577-i2c": for MediaTek MT2701 "mediatek,mt2701-i2c", "mediatek,mt6577-i2c": for MediaTek MT2701
"mediatek,mt2712-i2c": for MediaTek MT2712
"mediatek,mt6577-i2c": for MediaTek MT6577 "mediatek,mt6577-i2c": for MediaTek MT6577
"mediatek,mt6589-i2c": for MediaTek MT6589 "mediatek,mt6589-i2c": for MediaTek MT6589
"mediatek,mt7622-i2c": for MediaTek MT7622 "mediatek,mt7622-i2c": for MediaTek MT7622
......
* NXP PCA954x I2C bus switch * NXP PCA954x I2C bus switch
The driver supports NXP PCA954x and PCA984x I2C mux/switch devices.
Required Properties: Required Properties:
- compatible: Must contain one of the following. - compatible: Must contain one of the following.
"nxp,pca9540", "nxp,pca9542", "nxp,pca9543", "nxp,pca9544", "nxp,pca9540",
"nxp,pca9545", "nxp,pca9546", "nxp,pca9547", "nxp,pca9548" "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. - reg: The I2C address of the device.
......
...@@ -25,6 +25,15 @@ default frequency is 100kHz ...@@ -25,6 +25,15 @@ default frequency is 100kHz
whenever you're using the "allwinner,sun6i-a31-i2c" whenever you're using the "allwinner,sun6i-a31-i2c"
compatible. 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: Examples:
i2c@11000 { i2c@11000 {
...@@ -42,3 +51,14 @@ For the Armada XP: ...@@ -42,3 +51,14 @@ For the Armada XP:
interrupts = <29>; interrupts = <29>;
clock-frequency = <100000>; 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>;
};
=================
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.
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.
...@@ -2288,7 +2288,9 @@ F: include/linux/async_tx.h ...@@ -2288,7 +2288,9 @@ F: include/linux/async_tx.h
AT24 EEPROM DRIVER AT24 EEPROM DRIVER
M: Bartosz Golaszewski <brgl@bgdev.pl> M: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/eeprom/at24.txt
F: drivers/misc/eeprom/at24.c F: drivers/misc/eeprom/at24.c
F: include/linux/platform_data/at24.h F: include/linux/platform_data/at24.h
...@@ -6580,6 +6582,12 @@ F: drivers/i2c/i2c-mux.c ...@@ -6580,6 +6582,12 @@ F: drivers/i2c/i2c-mux.c
F: drivers/i2c/muxes/ F: drivers/i2c/muxes/
F: include/linux/i2c-mux.h 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 I2C OVER PARALLEL PORT
M: Jean Delvare <jdelvare@suse.com> M: Jean Delvare <jdelvare@suse.com>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/mtd/rawnand.h> #include <linux/mtd/rawnand.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/i2c/tvp514x.h> #include <media/i2c/tvp514x.h>
...@@ -108,11 +109,20 @@ static struct platform_device davinci_nand_device = { ...@@ -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 = { static struct davinci_i2c_platform_data i2c_pdata = {
.bus_freq = 400 /* kHz */, .bus_freq = 400 /* kHz */,
.bus_delay = 0 /* usec */, .bus_delay = 0 /* usec */,
.sda_pin = 15, .gpio_recovery = true,
.scl_pin = 14,
}; };
static int dm355evm_mmc_gpios = -EINVAL; static int dm355evm_mmc_gpios = -EINVAL;
...@@ -141,6 +151,7 @@ static struct i2c_board_info dm355evm_i2c_info[] = { ...@@ -141,6 +151,7 @@ static struct i2c_board_info dm355evm_i2c_info[] = {
static void __init evm_init_i2c(void) static void __init evm_init_i2c(void)
{ {
gpiod_add_lookup_table(&i2c_recovery_gpiod_table);
davinci_init_i2c(&i2c_pdata); davinci_init_i2c(&i2c_pdata);
gpio_request(5, "dm355evm_msp"); gpio_request(5, "dm355evm_msp");
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/platform_data/pcf857x.h> #include <linux/platform_data/pcf857x.h>
#include <linux/platform_data/at24.h> #include <linux/platform_data/at24.h>
...@@ -595,18 +596,28 @@ static struct i2c_board_info __initdata i2c_info[] = { ...@@ -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), /* The msp430 uses a slow bitbanged I2C implementation (ergo 20 KHz),
* which requires 100 usec of idle bus after i2c writes sent to it. * which requires 100 usec of idle bus after i2c writes sent to it.
*/ */
static struct davinci_i2c_platform_data i2c_pdata = { static struct davinci_i2c_platform_data i2c_pdata = {
.bus_freq = 20 /* kHz */, .bus_freq = 20 /* kHz */,
.bus_delay = 100 /* usec */, .bus_delay = 100 /* usec */,
.sda_pin = 44, .gpio_recovery = true,
.scl_pin = 43,
}; };
static void __init evm_init_i2c(void) static void __init evm_init_i2c(void)
{ {
gpiod_add_lookup_table(&i2c_recovery_gpiod_table);
davinci_init_i2c(&i2c_pdata); davinci_init_i2c(&i2c_pdata);
i2c_add_driver(&dm6446evm_msp_driver); i2c_add_driver(&dm6446evm_msp_driver);
i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
......
...@@ -649,6 +649,11 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, ...@@ -649,6 +649,11 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (bit_adap->getscl == NULL) if (bit_adap->getscl == NULL)
adap->quirks = &i2c_bit_quirk_no_clk_stretch; 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); ret = add_adapter(adap);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -603,6 +603,14 @@ config I2C_GPIO ...@@ -603,6 +603,14 @@ config I2C_GPIO
This is a very simple bitbanging I2C driver utilizing the This is a very simple bitbanging I2C driver utilizing the
arch-neutral GPIO API to control the SCL and SDA lines. 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 config I2C_HIGHLANDER
tristate "Highlander FPGA SMBus interface" tristate "Highlander FPGA SMBus interface"
depends on SH_HIGHLANDER depends on SH_HIGHLANDER
......
/* /*
* linux/drivers/acorn/char/i2c.c * ARM IOC/IOMD i2c driver.
* *
* Copyright (C) 2000 Russell King * Copyright (C) 2000 Russell King
* *
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* ARM IOC/IOMD i2c driver.
*
* On Acorn machines, the following i2c devices are on the bus: * On Acorn machines, the following i2c devices are on the bus:
* - PCF8583 real time clock & static RAM * - PCF8583 real time clock & static RAM
*/ */
...@@ -94,3 +92,7 @@ static int __init i2c_ioc_init(void) ...@@ -94,3 +92,7 @@ static int __init i2c_ioc_init(void)
} }
module_init(i2c_ioc_init); module_init(i2c_ioc_init);
MODULE_AUTHOR("Russell King <linux@armlinux.org.uk>");
MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver");
MODULE_LICENSE("GPL v2");
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_data/i2c-davinci.h> #include <linux/platform_data/i2c-davinci.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -139,7 +139,6 @@ struct davinci_i2c_dev { ...@@ -139,7 +139,6 @@ struct davinci_i2c_dev {
u8 terminate; u8 terminate;
struct i2c_adapter adapter; struct i2c_adapter adapter;
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
struct completion xfr_complete;
struct notifier_block freq_transition; struct notifier_block freq_transition;
#endif #endif
struct davinci_i2c_platform_data *pdata; struct davinci_i2c_platform_data *pdata;
...@@ -294,7 +293,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) ...@@ -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. * which is provided by I2C Bus recovery infrastructure.
*/ */
static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap) static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap)
...@@ -316,7 +315,7 @@ static void davinci_i2c_unprepare_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 = { 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, .prepare_recovery = davinci_i2c_prepare_recovery,
.unprepare_recovery = davinci_i2c_unprepare_recovery, .unprepare_recovery = davinci_i2c_unprepare_recovery,
}; };
...@@ -567,9 +566,6 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -567,9 +566,6 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
} }
ret = num; ret = num;
#ifdef CONFIG_CPU_FREQ
complete(&dev->xfr_complete);
#endif
out: out:
pm_runtime_mark_last_busy(dev->dev); pm_runtime_mark_last_busy(dev->dev);
...@@ -717,13 +713,15 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb, ...@@ -717,13 +713,15 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
struct davinci_i2c_dev *dev; struct davinci_i2c_dev *dev;
dev = container_of(nb, struct davinci_i2c_dev, freq_transition); dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
i2c_lock_adapter(&dev->adapter);
if (val == CPUFREQ_PRECHANGE) { if (val == CPUFREQ_PRECHANGE) {
wait_for_completion(&dev->xfr_complete);
davinci_i2c_reset_ctrl(dev, 0); davinci_i2c_reset_ctrl(dev, 0);
} else if (val == CPUFREQ_POSTCHANGE) { } else if (val == CPUFREQ_POSTCHANGE) {
i2c_davinci_calc_clk_dividers(dev); i2c_davinci_calc_clk_dividers(dev);
davinci_i2c_reset_ctrl(dev, 1); davinci_i2c_reset_ctrl(dev, 1);
} }
i2c_unlock_adapter(&dev->adapter);
return 0; return 0;
} }
...@@ -769,6 +767,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) ...@@ -769,6 +767,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
struct davinci_i2c_dev *dev; struct davinci_i2c_dev *dev;
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct resource *mem; struct resource *mem;
struct i2c_bus_recovery_info *rinfo;
int r, irq; int r, irq;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
...@@ -789,9 +788,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) ...@@ -789,9 +788,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
} }
init_completion(&dev->cmd_complete); init_completion(&dev->cmd_complete);
#ifdef CONFIG_CPU_FREQ
init_completion(&dev->xfr_complete);
#endif
dev->dev = &pdev->dev; dev->dev = &pdev->dev;
dev->irq = irq; dev->irq = irq;
dev->pdata = dev_get_platdata(&pdev->dev); dev->pdata = dev_get_platdata(&pdev->dev);
...@@ -868,10 +865,20 @@ static int davinci_i2c_probe(struct platform_device *pdev) ...@@ -868,10 +865,20 @@ static int davinci_i2c_probe(struct platform_device *pdev)
if (dev->pdata->has_pfunc) if (dev->pdata->has_pfunc)
adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;
else if (dev->pdata->scl_pin) { else if (dev->pdata->gpio_recovery) {
adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info; rinfo = &davinci_i2c_gpio_recovery_info;
adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin; adap->bus_recovery_info = rinfo;
adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin; 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; adap->nr = pdev->id;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
*/ */
#include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -185,6 +186,19 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) ...@@ -185,6 +186,19 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
return dev->get_clk_rate_khz(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 i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
{ {
int ret; int ret;
...@@ -217,7 +231,11 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) ...@@ -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) { while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
if (timeout <= 0) { if (timeout <= 0) {
dev_warn(dev->dev, "timeout waiting for bus ready\n"); dev_warn(dev->dev, "timeout waiting for bus ready\n");
i2c_recover_bus(&dev->adapter);
if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY)
return -ETIMEDOUT; return -ETIMEDOUT;
return 0;
} }
timeout--; timeout--;
usleep_range(1000, 1100); usleep_range(1000, 1100);
......
...@@ -284,6 +284,7 @@ struct dw_i2c_dev { ...@@ -284,6 +284,7 @@ struct dw_i2c_dev {
void (*disable_int)(struct dw_i2c_dev *dev); void (*disable_int)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev);
int mode; int mode;
struct i2c_bus_recovery_info rinfo;
}; };
#define ACCESS_SWAP 0x00000001 #define ACCESS_SWAP 0x00000001
...@@ -299,6 +300,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); ...@@ -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(struct dw_i2c_dev *dev, bool enable);
void __i2c_dw_enable_and_wait(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); 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); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
void i2c_dw_release_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); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
......
...@@ -25,11 +25,13 @@ ...@@ -25,11 +25,13 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h>
#include "i2c-designware-core.h" #include "i2c-designware-core.h"
...@@ -443,6 +445,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -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)) { if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
dev_err(dev->dev, "controller timed out\n"); dev_err(dev->dev, "controller timed out\n");
/* i2c_dw_init implicitly disables the adapter */ /* i2c_dw_init implicitly disables the adapter */
i2c_recover_bus(&dev->adapter);
i2c_dw_init_master(dev); i2c_dw_init_master(dev);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto done; goto done;
...@@ -613,6 +616,56 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) ...@@ -613,6 +616,56 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
return IRQ_HANDLED; 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) int i2c_dw_probe(struct dw_i2c_dev *dev)
{ {
struct i2c_adapter *adap = &dev->adapter; struct i2c_adapter *adap = &dev->adapter;
...@@ -652,6 +705,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) ...@@ -652,6 +705,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
return ret; return ret;
} }
ret = i2c_dw_init_recovery_info(dev);
if (ret)
return ret;
/* /*
* Increment PM usage count during adapter registration in order to * Increment PM usage count during adapter registration in order to
* avoid possible spurious runtime suspend when adapter device is * avoid possible spurious runtime suspend when adapter device is
......
...@@ -202,29 +202,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev) ...@@ -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; DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED;
dev->mode = DW_IC_SLAVE; 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) 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) ...@@ -356,7 +333,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
i2c_dw_configure_master(dev); i2c_dw_configure_master(dev);
dev->clk = devm_clk_get(&pdev->dev, NULL); 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; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
if (!dev->sda_hold_time && ht) if (!dev->sda_hold_time && ht)
...@@ -472,7 +449,7 @@ static int dw_i2c_plat_suspend(struct device *dev) ...@@ -472,7 +449,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i_dev->disable(i_dev); i_dev->disable(i_dev);
i2c_dw_plat_prepare_clk(i_dev, false); i2c_dw_prepare_clk(i_dev, false);
return 0; return 0;
} }
...@@ -481,7 +458,7 @@ static int dw_i2c_plat_resume(struct device *dev) ...@@ -481,7 +458,7 @@ static int dw_i2c_plat_resume(struct device *dev)
{ {
struct dw_i2c_dev *i_dev = dev_get_drvdata(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); i_dev->init(i_dev);
return 0; return 0;
......
...@@ -51,9 +51,7 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) ...@@ -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) static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
{ {
u32 sda_falling_time, scl_falling_time;
u32 reg, comp_param1; u32 reg, comp_param1;
u32 hcnt, lcnt;
int ret; int ret;
ret = i2c_dw_acquire_lock(dev); ret = i2c_dw_acquire_lock(dev);
...@@ -79,68 +77,6 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) ...@@ -79,68 +77,6 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
/* Disable the adapter. */ /* Disable the adapter. */
__i2c_dw_enable_and_wait(dev, false); __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. */ /* Configure SDA Hold Time if required. */
reg = dw_readl(dev, DW_IC_COMP_VERSION); reg = dw_readl(dev, DW_IC_COMP_VERSION);
if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
......
...@@ -170,7 +170,7 @@ ...@@ -170,7 +170,7 @@
#define HSI2C_HS_TX_CLOCK 1000000 #define HSI2C_HS_TX_CLOCK 1000000
#define HSI2C_FS_TX_CLOCK 100000 #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) #define HSI2C_EXYNOS7 BIT(0)
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include <linux/i2c-gpio.h> #include <linux/i2c-gpio.h>
...@@ -23,6 +25,9 @@ struct i2c_gpio_private_data { ...@@ -23,6 +25,9 @@ struct i2c_gpio_private_data {
struct i2c_adapter adap; struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data; struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata; 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) ...@@ -34,7 +39,7 @@ static void i2c_gpio_setsda_val(void *data, int state)
{ {
struct i2c_gpio_private_data *priv = data; 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) ...@@ -47,23 +52,125 @@ static void i2c_gpio_setscl_val(void *data, int state)
{ {
struct i2c_gpio_private_data *priv = data; 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) static int i2c_gpio_getsda(void *data)
{ {
struct i2c_gpio_private_data *priv = 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) static int i2c_gpio_getscl(void *data)
{ {
struct i2c_gpio_private_data *priv = 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, static void of_i2c_gpio_get_props(struct device_node *np,
struct i2c_gpio_platform_data *pdata) struct i2c_gpio_platform_data *pdata)
{ {
...@@ -179,6 +286,9 @@ static int i2c_gpio_probe(struct platform_device *pdev) ...@@ -179,6 +286,9 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (IS_ERR(priv->scl)) if (IS_ERR(priv->scl))
return PTR_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->setsda = i2c_gpio_setsda_val;
bit_data->setscl = i2c_gpio_setscl_val; bit_data->setscl = i2c_gpio_setscl_val;
...@@ -228,6 +338,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) ...@@ -228,6 +338,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
pdata->scl_is_output_only pdata->scl_is_output_only
? ", no clock stretching" : ""); ? ", no clock stretching" : "");
i2c_gpio_fault_injector_init(pdev);
return 0; return 0;
} }
...@@ -236,6 +348,8 @@ static int i2c_gpio_remove(struct platform_device *pdev) ...@@ -236,6 +348,8 @@ static int i2c_gpio_remove(struct platform_device *pdev)
struct i2c_gpio_private_data *priv; struct i2c_gpio_private_data *priv;
struct i2c_adapter *adap; struct i2c_adapter *adap;
i2c_gpio_fault_injector_exit(pdev);
priv = platform_get_drvdata(pdev); priv = platform_get_drvdata(pdev);
adap = &priv->adap; adap = &priv->adap;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -90,6 +91,8 @@ ...@@ -90,6 +91,8 @@
#define FAST_PLUS_MAX_BITRATE 3400000 #define FAST_PLUS_MAX_BITRATE 3400000
#define HIGHSPEED_MAX_BITRATE 5000000 #define HIGHSPEED_MAX_BITRATE 5000000
#define I2C_PM_TIMEOUT 10 /* ms */
enum lpi2c_imx_mode { enum lpi2c_imx_mode {
STANDARD, /* 100+Kbps */ STANDARD, /* 100+Kbps */
FAST, /* 400+Kbps */ FAST, /* 400+Kbps */
...@@ -274,8 +277,8 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) ...@@ -274,8 +277,8 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
unsigned int temp; unsigned int temp;
int ret; int ret;
ret = clk_enable(lpi2c_imx->clk); ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
if (ret) if (ret < 0)
return ret; return ret;
temp = MCR_RST; temp = MCR_RST;
...@@ -284,7 +287,7 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) ...@@ -284,7 +287,7 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
ret = lpi2c_imx_config(lpi2c_imx); ret = lpi2c_imx_config(lpi2c_imx);
if (ret) if (ret)
goto clk_disable; goto rpm_put;
temp = readl(lpi2c_imx->base + LPI2C_MCR); temp = readl(lpi2c_imx->base + LPI2C_MCR);
temp |= MCR_MEN; temp |= MCR_MEN;
...@@ -292,8 +295,9 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) ...@@ -292,8 +295,9 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
return 0; return 0;
clk_disable: rpm_put:
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 ret; return ret;
} }
...@@ -306,7 +310,8 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx) ...@@ -306,7 +310,8 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
temp &= ~MCR_MEN; temp &= ~MCR_MEN;
writel(temp, lpi2c_imx->base + LPI2C_MCR); 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; return 0;
} }
...@@ -606,22 +611,31 @@ static int lpi2c_imx_probe(struct platform_device *pdev) ...@@ -606,22 +611,31 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
return ret; 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); temp = readl(lpi2c_imx->base + LPI2C_PARAM);
lpi2c_imx->txfifosize = 1 << (temp & 0x0f); lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
clk_disable(lpi2c_imx->clk);
ret = i2c_add_adapter(&lpi2c_imx->adapter); ret = i2c_add_adapter(&lpi2c_imx->adapter);
if (ret) 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"); dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
return 0; return 0;
clk_unprepare: rpm_disable:
clk_unprepare(lpi2c_imx->clk); pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
return ret; return ret;
} }
...@@ -632,28 +646,48 @@ static int lpi2c_imx_remove(struct platform_device *pdev) ...@@ -632,28 +646,48 @@ static int lpi2c_imx_remove(struct platform_device *pdev)
i2c_del_adapter(&lpi2c_imx->adapter); 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; return 0;
} }
#ifdef CONFIG_PM_SLEEP #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); pinctrl_pm_select_sleep_state(dev);
return 0; 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); 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; 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 = { static struct platform_driver lpi2c_imx_driver = {
.probe = lpi2c_imx_probe, .probe = lpi2c_imx_probe,
...@@ -661,7 +695,7 @@ static struct platform_driver lpi2c_imx_driver = { ...@@ -661,7 +695,7 @@ static struct platform_driver lpi2c_imx_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = lpi2c_imx_of_match, .of_match_table = lpi2c_imx_of_match,
.pm = &imx_lpi2c_pm, .pm = IMX_LPI2C_PM,
}, },
}; };
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/dmapool.h> #include <linux/dmapool.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -46,7 +47,6 @@ ...@@ -46,7 +47,6 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_dma.h> #include <linux/of_dma.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h> #include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -1006,26 +1006,26 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, ...@@ -1006,26 +1006,26 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
PINCTRL_STATE_DEFAULT); PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
"gpio"); "gpio");
rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0); rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0); rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH);
if (rinfo->sda_gpio == -EPROBE_DEFER || if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
rinfo->scl_gpio == -EPROBE_DEFER) { PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
return -EPROBE_DEFER; return -EPROBE_DEFER;
} else if (!gpio_is_valid(rinfo->sda_gpio) || } else if (IS_ERR(rinfo->sda_gpiod) ||
!gpio_is_valid(rinfo->scl_gpio) || IS_ERR(rinfo->scl_gpiod) ||
IS_ERR(i2c_imx->pinctrl_pins_default) || IS_ERR(i2c_imx->pinctrl_pins_default) ||
IS_ERR(i2c_imx->pinctrl_pins_gpio)) { IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
dev_dbg(&pdev->dev, "recovery information incomplete\n"); dev_dbg(&pdev->dev, "recovery information incomplete\n");
return 0; return 0;
} }
dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", dev_dbg(&pdev->dev, "using scl%s for recovery\n",
rinfo->scl_gpio, rinfo->sda_gpio); rinfo->sda_gpiod ? ",sda" : "");
rinfo->prepare_recovery = i2c_imx_prepare_recovery; rinfo->prepare_recovery = i2c_imx_prepare_recovery;
rinfo->unprepare_recovery = i2c_imx_unprepare_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; i2c_imx->adapter.bus_recovery_info = rinfo;
return 0; return 0;
......
...@@ -172,7 +172,7 @@ struct ismt_priv { ...@@ -172,7 +172,7 @@ struct ismt_priv {
dma_addr_t io_rng_dma; /* descriptor HW base addr */ dma_addr_t io_rng_dma; /* descriptor HW base addr */
u8 head; /* ring buffer head pointer */ u8 head; /* ring buffer head pointer */
struct completion cmp; /* interrupt completion */ 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, ...@@ -320,10 +320,12 @@ static int ismt_process_desc(const struct ismt_desc *desc,
struct ismt_priv *priv, int size, struct ismt_priv *priv, int size,
char read_write) 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"); dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n");
__ismt_desc_dump(&priv->pci_dev->dev, desc); __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 (desc->status & ISMT_DESC_SCS) {
if (read_write == I2C_SMBUS_WRITE && if (read_write == I2C_SMBUS_WRITE &&
...@@ -393,11 +395,12 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ...@@ -393,11 +395,12 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
struct ismt_desc *desc; struct ismt_desc *desc;
struct ismt_priv *priv = i2c_get_adapdata(adap); struct ismt_priv *priv = i2c_get_adapdata(adap);
struct device *dev = &priv->pci_dev->dev; struct device *dev = &priv->pci_dev->dev;
u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);
desc = &priv->hw[priv->head]; desc = &priv->hw[priv->head];
/* Initialize the DMA buffer */ /* Initialize the DMA buffer */
memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer)); memset(priv->buffer, 0, sizeof(priv->buffer));
/* Initialize the descriptor */ /* Initialize the descriptor */
memset(desc, 0, sizeof(struct ismt_desc)); memset(desc, 0, sizeof(struct ismt_desc));
...@@ -446,8 +449,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ...@@ -446,8 +449,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->wr_len_cmd = 2; desc->wr_len_cmd = 2;
dma_size = 2; dma_size = 2;
dma_direction = DMA_TO_DEVICE; dma_direction = DMA_TO_DEVICE;
priv->dma_buffer[0] = command; dma_buffer[0] = command;
priv->dma_buffer[1] = data->byte; dma_buffer[1] = data->byte;
} else { } else {
/* Read Byte */ /* Read Byte */
dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n");
...@@ -466,9 +469,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ...@@ -466,9 +469,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->wr_len_cmd = 3; desc->wr_len_cmd = 3;
dma_size = 3; dma_size = 3;
dma_direction = DMA_TO_DEVICE; dma_direction = DMA_TO_DEVICE;
priv->dma_buffer[0] = command; dma_buffer[0] = command;
priv->dma_buffer[1] = data->word & 0xff; dma_buffer[1] = data->word & 0xff;
priv->dma_buffer[2] = data->word >> 8; dma_buffer[2] = data->word >> 8;
} else { } else {
/* Read Word */ /* Read Word */
dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n");
...@@ -486,9 +489,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ...@@ -486,9 +489,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->rd_len = 2; desc->rd_len = 2;
dma_size = 3; dma_size = 3;
dma_direction = DMA_BIDIRECTIONAL; dma_direction = DMA_BIDIRECTIONAL;
priv->dma_buffer[0] = command; dma_buffer[0] = command;
priv->dma_buffer[1] = data->word & 0xff; dma_buffer[1] = data->word & 0xff;
priv->dma_buffer[2] = data->word >> 8; dma_buffer[2] = data->word >> 8;
break; break;
case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_DATA:
...@@ -499,8 +502,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ...@@ -499,8 +502,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
dma_direction = DMA_TO_DEVICE; dma_direction = DMA_TO_DEVICE;
desc->wr_len_cmd = dma_size; desc->wr_len_cmd = dma_size;
desc->control |= ISMT_DESC_BLK; desc->control |= ISMT_DESC_BLK;
priv->dma_buffer[0] = command; dma_buffer[0] = command;
memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
} else { } else {
/* Block Read */ /* Block Read */
dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n");
...@@ -527,8 +530,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ...@@ -527,8 +530,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
dma_direction = DMA_TO_DEVICE; dma_direction = DMA_TO_DEVICE;
desc->wr_len_cmd = dma_size; desc->wr_len_cmd = dma_size;
desc->control |= ISMT_DESC_I2C; desc->control |= ISMT_DESC_I2C;
priv->dma_buffer[0] = command; dma_buffer[0] = command;
memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
} else { } else {
/* i2c Block Read */ /* i2c Block Read */
dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n");
...@@ -557,23 +560,22 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ...@@ -557,23 +560,22 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
if (dma_size != 0) { if (dma_size != 0) {
dev_dbg(dev, " dev=%p\n", dev); dev_dbg(dev, " dev=%p\n", dev);
dev_dbg(dev, " data=%p\n", data); 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_size=%d\n", dma_size);
dev_dbg(dev, " dma_direction=%d\n", dma_direction); dev_dbg(dev, " dma_direction=%d\n", dma_direction);
dma_addr = dma_map_single(dev, dma_addr = dma_map_single(dev,
priv->dma_buffer, dma_buffer,
dma_size, dma_size,
dma_direction); dma_direction);
if (dma_mapping_error(dev, dma_addr)) { if (dma_mapping_error(dev, dma_addr)) {
dev_err(dev, "Error in mapping dma buffer %p\n", dev_err(dev, "Error in mapping dma buffer %p\n",
priv->dma_buffer); dma_buffer);
return -EIO; return -EIO;
} }
dev_dbg(dev, " dma_addr = 0x%016llX\n", dev_dbg(dev, " dma_addr = %pad\n", &dma_addr);
(unsigned long long)dma_addr);
desc->dptr_low = lower_32_bits(dma_addr); desc->dptr_low = lower_32_bits(dma_addr);
desc->dptr_high = upper_32_bits(dma_addr); desc->dptr_high = upper_32_bits(dma_addr);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -57,6 +58,10 @@ enum { ...@@ -57,6 +58,10 @@ enum {
STATE_WRITE, STATE_WRITE,
}; };
struct meson_i2c_data {
unsigned char div_factor;
};
/** /**
* struct meson_i2c - Meson I2C device private data * struct meson_i2c - Meson I2C device private data
* *
...@@ -64,7 +69,6 @@ enum { ...@@ -64,7 +69,6 @@ enum {
* @dev: Pointer to device structure * @dev: Pointer to device structure
* @regs: Base address of the device memory mapped registers * @regs: Base address of the device memory mapped registers
* @clk: Pointer to clock structure * @clk: Pointer to clock structure
* @irq: IRQ number
* @msg: Pointer to the current I2C message * @msg: Pointer to the current I2C message
* @state: Current state in the driver state machine * @state: Current state in the driver state machine
* @last: Flag set for the last message in the transfer * @last: Flag set for the last message in the transfer
...@@ -75,6 +79,7 @@ enum { ...@@ -75,6 +79,7 @@ enum {
* @done: Completion used to wait for transfer termination * @done: Completion used to wait for transfer termination
* @tokens: Sequence of tokens to be written to the device * @tokens: Sequence of tokens to be written to the device
* @num_tokens: Number of tokens * @num_tokens: Number of tokens
* @data: Pointer to the controlller's platform data
*/ */
struct meson_i2c { struct meson_i2c {
struct i2c_adapter adap; struct i2c_adapter adap;
...@@ -93,6 +98,8 @@ struct meson_i2c { ...@@ -93,6 +98,8 @@ struct meson_i2c {
struct completion done; struct completion done;
u32 tokens[2]; u32 tokens[2];
int num_tokens; int num_tokens;
const struct meson_i2c_data *data;
}; };
static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, 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) ...@@ -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 long clk_rate = clk_get_rate(i2c->clk);
unsigned int div; 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 */ /* clock divider has 12 bits */
if (div >= (1 << 12)) { if (div >= (1 << 12)) {
...@@ -376,6 +383,9 @@ static int meson_i2c_probe(struct platform_device *pdev) ...@@ -376,6 +383,9 @@ static int meson_i2c_probe(struct platform_device *pdev)
spin_lock_init(&i2c->lock); spin_lock_init(&i2c->lock);
init_completion(&i2c->done); 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); i2c->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c->clk)) { if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "can't get device clock\n"); dev_err(&pdev->dev, "can't get device clock\n");
...@@ -440,11 +450,25 @@ static int meson_i2c_remove(struct platform_device *pdev) ...@@ -440,11 +450,25 @@ static int meson_i2c_remove(struct platform_device *pdev)
return 0; 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[] = { static const struct of_device_id meson_i2c_match[] = {
{ .compatible = "amlogic,meson6-i2c" }, { .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data },
{ .compatible = "amlogic,meson-gxbb-i2c" }, { .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); MODULE_DEVICE_TABLE(of, meson_i2c_match);
static struct platform_driver meson_i2c_driver = { static struct platform_driver meson_i2c_driver = {
......
...@@ -78,9 +78,7 @@ struct mpc_i2c_divider { ...@@ -78,9 +78,7 @@ struct mpc_i2c_divider {
}; };
struct mpc_i2c_data { struct mpc_i2c_data {
void (*setup)(struct device_node *node, struct mpc_i2c *i2c, void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock);
u32 clock, u32 prescaler);
u32 prescaler;
}; };
static inline void writeccr(struct mpc_i2c *i2c, u32 x) static inline void writeccr(struct mpc_i2c *i2c, u32 x)
...@@ -201,7 +199,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = { ...@@ -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, 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; const struct mpc_i2c_divider *div = NULL;
unsigned int pvr = mfspr(SPRN_PVR); unsigned int pvr = mfspr(SPRN_PVR);
...@@ -236,7 +234,7 @@ static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, ...@@ -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, static void mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c, struct mpc_i2c *i2c,
u32 clock, u32 prescaler) u32 clock)
{ {
int ret, fdr; int ret, fdr;
...@@ -246,7 +244,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, ...@@ -246,7 +244,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
return; 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 */ fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
...@@ -258,7 +256,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, ...@@ -258,7 +256,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */ #else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
static void mpc_i2c_setup_52xx(struct device_node *node, static void mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c, struct mpc_i2c *i2c,
u32 clock, u32 prescaler) u32 clock)
{ {
} }
#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */ #endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
...@@ -266,7 +264,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, ...@@ -266,7 +264,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
#ifdef CONFIG_PPC_MPC512x #ifdef CONFIG_PPC_MPC512x
static void mpc_i2c_setup_512x(struct device_node *node, static void mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c, struct mpc_i2c *i2c,
u32 clock, u32 prescaler) u32 clock)
{ {
struct device_node *node_ctrl; struct device_node *node_ctrl;
void __iomem *ctrl; void __iomem *ctrl;
...@@ -289,12 +287,12 @@ static void mpc_i2c_setup_512x(struct device_node *node, ...@@ -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 */ /* 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 */ #else /* CONFIG_PPC_MPC512x */
static void mpc_i2c_setup_512x(struct device_node *node, static void mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c, struct mpc_i2c *i2c,
u32 clock, u32 prescaler) u32 clock)
{ {
} }
#endif /* CONFIG_PPC_MPC512x */ #endif /* CONFIG_PPC_MPC512x */
...@@ -332,14 +330,18 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) ...@@ -332,14 +330,18 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
if (prop) { if (prop) {
/* /*
* Map and check POR Device Status Register 2 * 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); reg = ioremap(get_immrbase() + *prop + 0x14, 0x4);
if (!reg) if (!reg)
printk(KERN_ERR printk(KERN_ERR
"Error: couldn't map PORDEVSR2\n"); "Error: couldn't map PORDEVSR2\n");
else else
val = in_be32(reg) & 0x00000080; /* sec-cfg */ val = in_be32(reg) & 0x00000020; /* sec-cfg */
iounmap(reg); iounmap(reg);
} }
} }
...@@ -350,7 +352,11 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) ...@@ -350,7 +352,11 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
static u32 mpc_i2c_get_prescaler_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; u32 prescaler = 1;
/* mpc85xx */ /* mpc85xx */
...@@ -367,6 +373,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void) ...@@ -367,6 +373,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void)
|| (SVR_SOC_VER(svr) == SVR_8610)) || (SVR_SOC_VER(svr) == SVR_8610))
/* the above 85xx SoCs have prescaler 1 */ /* the above 85xx SoCs have prescaler 1 */
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 else
/* all the other 85xx have prescaler 2 */ /* all the other 85xx have prescaler 2 */
prescaler = 2; prescaler = 2;
...@@ -376,9 +386,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void) ...@@ -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, 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; const struct mpc_i2c_divider *div = NULL;
u32 prescaler = mpc_i2c_get_prescaler_8xxx();
u32 divider; u32 divider;
int i; int i;
...@@ -388,12 +399,6 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, ...@@ -388,12 +399,6 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
return -EINVAL; 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; divider = fsl_get_sys_freq() / clock / prescaler;
pr_debug("I2C: src_clock=%d clock=%d divider=%d\n", 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, ...@@ -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, static void mpc_i2c_setup_8xxx(struct device_node *node,
struct mpc_i2c *i2c, struct mpc_i2c *i2c,
u32 clock, u32 prescaler) u32 clock)
{ {
int ret, fdr; int ret, fdr;
...@@ -426,7 +431,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node, ...@@ -426,7 +431,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node,
return; 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 */ fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
...@@ -440,7 +445,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node, ...@@ -440,7 +445,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node,
#else /* !CONFIG_FSL_SOC */ #else /* !CONFIG_FSL_SOC */
static void mpc_i2c_setup_8xxx(struct device_node *node, static void mpc_i2c_setup_8xxx(struct device_node *node,
struct mpc_i2c *i2c, struct mpc_i2c *i2c,
u32 clock, u32 prescaler) u32 clock)
{ {
} }
#endif /* CONFIG_FSL_SOC */ #endif /* CONFIG_FSL_SOC */
...@@ -711,11 +716,11 @@ static int fsl_i2c_probe(struct platform_device *op) ...@@ -711,11 +716,11 @@ static int fsl_i2c_probe(struct platform_device *op)
if (match->data) { if (match->data) {
const struct mpc_i2c_data *data = 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 { } else {
/* Backwards compatibility */ /* Backwards compatibility */
if (of_get_property(op->dev.of_node, "dfsrr", NULL)) 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); 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 = { ...@@ -813,12 +818,10 @@ static const struct mpc_i2c_data mpc_i2c_data_8313 = {
static const struct mpc_i2c_data mpc_i2c_data_8543 = { static const struct mpc_i2c_data mpc_i2c_data_8543 = {
.setup = mpc_i2c_setup_8xxx, .setup = mpc_i2c_setup_8xxx,
.prescaler = 2,
}; };
static const struct mpc_i2c_data mpc_i2c_data_8544 = { static const struct mpc_i2c_data mpc_i2c_data_8544 = {
.setup = mpc_i2c_setup_8xxx, .setup = mpc_i2c_setup_8xxx,
.prescaler = 3,
}; };
static const struct of_device_id mpc_i2c_of_match[] = { static const struct of_device_id mpc_i2c_of_match[] = {
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#define I2C_DMA_HARD_RST 0x0002 #define I2C_DMA_HARD_RST 0x0002
#define I2C_DMA_4G_MODE 0x0001 #define I2C_DMA_4G_MODE 0x0001
#define I2C_DEFAULT_CLK_DIV 5
#define I2C_DEFAULT_SPEED 100000 /* hz */ #define I2C_DEFAULT_SPEED 100000 /* hz */
#define MAX_FS_MODE_SPEED 400000 #define MAX_FS_MODE_SPEED 400000
#define MAX_HS_MODE_SPEED 3400000 #define MAX_HS_MODE_SPEED 3400000
...@@ -127,6 +128,7 @@ enum I2C_REGS_OFFSET { ...@@ -127,6 +128,7 @@ enum I2C_REGS_OFFSET {
OFFSET_DEBUGSTAT = 0x64, OFFSET_DEBUGSTAT = 0x64,
OFFSET_DEBUGCTRL = 0x68, OFFSET_DEBUGCTRL = 0x68,
OFFSET_TRANSFER_LEN_AUX = 0x6c, OFFSET_TRANSFER_LEN_AUX = 0x6c,
OFFSET_CLOCK_DIV = 0x70,
}; };
struct mtk_i2c_compatible { struct mtk_i2c_compatible {
...@@ -136,6 +138,7 @@ struct mtk_i2c_compatible { ...@@ -136,6 +138,7 @@ struct mtk_i2c_compatible {
unsigned char auto_restart: 1; unsigned char auto_restart: 1;
unsigned char aux_len_reg: 1; unsigned char aux_len_reg: 1;
unsigned char support_33bits: 1; unsigned char support_33bits: 1;
unsigned char timing_adjust: 1;
}; };
struct mtk_i2c { struct mtk_i2c {
...@@ -176,6 +179,15 @@ static const struct i2c_adapter_quirks mt7622_i2c_quirks = { ...@@ -176,6 +179,15 @@ static const struct i2c_adapter_quirks mt7622_i2c_quirks = {
.max_num_msgs = 255, .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 = { static const struct mtk_i2c_compatible mt6577_compat = {
.quirks = &mt6577_i2c_quirks, .quirks = &mt6577_i2c_quirks,
.pmic_i2c = 0, .pmic_i2c = 0,
...@@ -183,6 +195,7 @@ static const struct mtk_i2c_compatible mt6577_compat = { ...@@ -183,6 +195,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
.auto_restart = 0, .auto_restart = 0,
.aux_len_reg = 0, .aux_len_reg = 0,
.support_33bits = 0, .support_33bits = 0,
.timing_adjust = 0,
}; };
static const struct mtk_i2c_compatible mt6589_compat = { static const struct mtk_i2c_compatible mt6589_compat = {
...@@ -192,6 +205,7 @@ static const struct mtk_i2c_compatible mt6589_compat = { ...@@ -192,6 +205,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
.auto_restart = 0, .auto_restart = 0,
.aux_len_reg = 0, .aux_len_reg = 0,
.support_33bits = 0, .support_33bits = 0,
.timing_adjust = 0,
}; };
static const struct mtk_i2c_compatible mt7622_compat = { static const struct mtk_i2c_compatible mt7622_compat = {
...@@ -201,6 +215,7 @@ static const struct mtk_i2c_compatible mt7622_compat = { ...@@ -201,6 +215,7 @@ static const struct mtk_i2c_compatible mt7622_compat = {
.auto_restart = 1, .auto_restart = 1,
.aux_len_reg = 1, .aux_len_reg = 1,
.support_33bits = 0, .support_33bits = 0,
.timing_adjust = 0,
}; };
static const struct mtk_i2c_compatible mt8173_compat = { static const struct mtk_i2c_compatible mt8173_compat = {
...@@ -209,9 +224,11 @@ static const struct mtk_i2c_compatible mt8173_compat = { ...@@ -209,9 +224,11 @@ static const struct mtk_i2c_compatible mt8173_compat = {
.auto_restart = 1, .auto_restart = 1,
.aux_len_reg = 1, .aux_len_reg = 1,
.support_33bits = 1, .support_33bits = 1,
.timing_adjust = 0,
}; };
static const struct of_device_id mtk_i2c_of_match[] = { 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,mt6577-i2c", .data = &mt6577_compat },
{ .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat }, { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat }, { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
...@@ -271,6 +288,9 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c) ...@@ -271,6 +288,9 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
if (i2c->dev_comp->dcm) if (i2c->dev_comp->dcm)
writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN); 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->timing_reg, i2c->base + OFFSET_TIMING);
writew(i2c->high_speed_reg, i2c->base + OFFSET_HS); writew(i2c->high_speed_reg, i2c->base + OFFSET_HS);
...@@ -725,10 +745,6 @@ static int mtk_i2c_probe(struct platform_device *pdev) ...@@ -725,10 +745,6 @@ static int mtk_i2c_probe(struct platform_device *pdev)
if (!i2c) if (!i2c)
return -ENOMEM; return -ENOMEM;
ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
if (ret)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res); i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base)) if (IS_ERR(i2c->base))
...@@ -759,6 +775,13 @@ static int mtk_i2c_probe(struct platform_device *pdev) ...@@ -759,6 +775,13 @@ static int mtk_i2c_probe(struct platform_device *pdev)
i2c->adap.timeout = 2 * HZ; i2c->adap.timeout = 2 * HZ;
i2c->adap.retries = 1; 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) if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c)
return -EINVAL; return -EINVAL;
...@@ -838,10 +861,19 @@ static int mtk_i2c_remove(struct platform_device *pdev) ...@@ -838,10 +861,19 @@ static int mtk_i2c_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int mtk_i2c_resume(struct device *dev) static int mtk_i2c_resume(struct device *dev)
{ {
int ret;
struct mtk_i2c *i2c = dev_get_drvdata(dev); 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_init_hw(i2c);
mtk_i2c_clock_disable(i2c);
return 0; return 0;
} }
#endif #endif
......
...@@ -135,6 +135,7 @@ struct mv64xxx_i2c_data { ...@@ -135,6 +135,7 @@ struct mv64xxx_i2c_data {
u32 freq_m; u32 freq_m;
u32 freq_n; u32 freq_n;
struct clk *clk; struct clk *clk;
struct clk *reg_clk;
wait_queue_head_t waitq; wait_queue_head_t waitq;
spinlock_t lock; spinlock_t lock;
struct i2c_msg *msg; struct i2c_msg *msg;
...@@ -894,13 +895,20 @@ mv64xxx_i2c_probe(struct platform_device *pd) ...@@ -894,13 +895,20 @@ mv64xxx_i2c_probe(struct platform_device *pd)
init_waitqueue_head(&drv_data->waitq); init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock); 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); drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER) if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER; return -EPROBE_DEFER;
if (!IS_ERR(drv_data->clk)) if (!IS_ERR(drv_data->clk))
clk_prepare_enable(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); drv_data->irq = platform_get_irq(pd, 0);
if (pdata) { if (pdata) {
...@@ -950,8 +958,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) ...@@ -950,8 +958,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
exit_reset: exit_reset:
reset_control_assert(drv_data->rstc); reset_control_assert(drv_data->rstc);
exit_clk: exit_clk:
/* Not all platforms have a clk */ clk_disable_unprepare(drv_data->reg_clk);
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk); clk_disable_unprepare(drv_data->clk);
return rc; return rc;
...@@ -965,8 +972,7 @@ mv64xxx_i2c_remove(struct platform_device *dev) ...@@ -965,8 +972,7 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter); i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data); free_irq(drv_data->irq, drv_data);
reset_control_assert(drv_data->rstc); reset_control_assert(drv_data->rstc);
/* Not all platforms have a clk */ clk_disable_unprepare(drv_data->reg_clk);
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk); clk_disable_unprepare(drv_data->clk);
return 0; return 0;
......
...@@ -181,7 +181,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, ...@@ -181,7 +181,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
if (msg->flags & I2C_M_RD) { if (msg->flags & I2C_M_RD) {
i2c->dma_read = 1; i2c->dma_read = true;
i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
/* /*
...@@ -239,7 +239,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, ...@@ -239,7 +239,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
goto read_init_dma_fail; goto read_init_dma_fail;
} }
} else { } else {
i2c->dma_read = 0; i2c->dma_read = false;
i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
/* /*
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#define MIE (1 << 3) /* master if enable */ #define MIE (1 << 3) /* master if enable */
#define TSBE (1 << 2) #define TSBE (1 << 2)
#define FSB (1 << 1) /* force stop bit */ #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) */ /* ICSSR (also for ICSIER) */
#define GCAR (1 << 6) /* general call received */ #define GCAR (1 << 6) /* general call received */
...@@ -132,6 +132,7 @@ struct rcar_i2c_priv { ...@@ -132,6 +132,7 @@ struct rcar_i2c_priv {
int pos; int pos;
u32 icccr; u32 icccr;
u32 flags; u32 flags;
u8 recovery_icmcr; /* protected by adapter lock */
enum rcar_i2c_type devtype; enum rcar_i2c_type devtype;
struct i2c_client *slave; struct i2c_client *slave;
...@@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) ...@@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
return readl(priv->io + 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) static void rcar_i2c_init(struct rcar_i2c_priv *priv)
{ {
/* reset master mode */ /* reset master mode */
...@@ -170,7 +211,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) ...@@ -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) static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
{ {
int i; int i, ret;
for (i = 0; i < LOOP_TIMEOUT; i++) { for (i = 0; i < LOOP_TIMEOUT; i++) {
/* make sure that bus is not busy */ /* make sure that bus is not busy */
...@@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) ...@@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
udelay(1); 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) 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) ...@@ -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); 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 * 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. * 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) ...@@ -359,7 +408,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
int len; int len;
/* Do not use DMA if it's not available or for messages < 8 bytes */ /* 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; return;
if (read) { if (read) {
...@@ -440,7 +489,7 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) ...@@ -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 * 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) if (msr & MAT)
rcar_i2c_dma(priv); rcar_i2c_dma(priv);
...@@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) ...@@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
adap->retries = 3; adap->retries = 3;
adap->dev.parent = dev; adap->dev.parent = dev;
adap->dev.of_node = dev->of_node; adap->dev.of_node = dev->of_node;
adap->bus_recovery_info = &rcar_i2c_bri;
i2c_set_adapdata(adap, priv); i2c_set_adapdata(adap, priv);
strlcpy(adap->name, pdev->name, sizeof(adap->name)); strlcpy(adap->name, pdev->name, sizeof(adap->name));
......
...@@ -161,6 +161,7 @@ enum rk3x_i2c_state { ...@@ -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 * @grf_offset: offset inside the grf regmap for setting the i2c type
* @calc_timings: Callback function for i2c timing information calculated * @calc_timings: Callback function for i2c timing information calculated
*/ */
...@@ -194,7 +195,7 @@ struct rk3x_i2c_soc_data { ...@@ -194,7 +195,7 @@ struct rk3x_i2c_soc_data {
struct rk3x_i2c { struct rk3x_i2c {
struct i2c_adapter adap; struct i2c_adapter adap;
struct device *dev; struct device *dev;
struct rk3x_i2c_soc_data *soc_data; const struct rk3x_i2c_soc_data *soc_data;
/* Hardware resources */ /* Hardware resources */
void __iomem *regs; void __iomem *regs;
...@@ -1164,27 +1165,27 @@ static const struct rk3x_i2c_soc_data rk3399_soc_data = { ...@@ -1164,27 +1165,27 @@ static const struct rk3x_i2c_soc_data rk3399_soc_data = {
static const struct of_device_id rk3x_i2c_match[] = { static const struct of_device_id rk3x_i2c_match[] = {
{ {
.compatible = "rockchip,rv1108-i2c", .compatible = "rockchip,rv1108-i2c",
.data = (void *)&rv1108_soc_data .data = &rv1108_soc_data
}, },
{ {
.compatible = "rockchip,rk3066-i2c", .compatible = "rockchip,rk3066-i2c",
.data = (void *)&rk3066_soc_data .data = &rk3066_soc_data
}, },
{ {
.compatible = "rockchip,rk3188-i2c", .compatible = "rockchip,rk3188-i2c",
.data = (void *)&rk3188_soc_data .data = &rk3188_soc_data
}, },
{ {
.compatible = "rockchip,rk3228-i2c", .compatible = "rockchip,rk3228-i2c",
.data = (void *)&rk3228_soc_data .data = &rk3228_soc_data
}, },
{ {
.compatible = "rockchip,rk3288-i2c", .compatible = "rockchip,rk3288-i2c",
.data = (void *)&rk3288_soc_data .data = &rk3288_soc_data
}, },
{ {
.compatible = "rockchip,rk3399-i2c", .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) ...@@ -1207,7 +1208,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
match = of_match_node(rk3x_i2c_match, np); 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 */ /* use common interface to get I2C timing properties */
i2c_parse_fw_timings(&pdev->dev, &i2c->t, true); i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);
......
...@@ -113,7 +113,6 @@ enum sh_mobile_i2c_op { ...@@ -113,7 +113,6 @@ enum sh_mobile_i2c_op {
OP_TX_FIRST, OP_TX_FIRST,
OP_TX, OP_TX,
OP_TX_STOP, OP_TX_STOP,
OP_TX_STOP_DATA,
OP_TX_TO_RX, OP_TX_TO_RX,
OP_RX, OP_RX,
OP_RX_STOP, OP_RX_STOP,
...@@ -145,11 +144,12 @@ struct sh_mobile_i2c_data { ...@@ -145,11 +144,12 @@ struct sh_mobile_i2c_data {
struct dma_chan *dma_rx; struct dma_chan *dma_rx;
struct scatterlist sg; struct scatterlist sg;
enum dma_data_direction dma_direction; enum dma_data_direction dma_direction;
u8 *dma_buf;
}; };
struct sh_mobile_dt_config { struct sh_mobile_dt_config {
int clks_per_count; 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) #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) ...@@ -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); 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; u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
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);
max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
if (pd->iccl > max_val || pd->icch > max_val) { 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", dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n",
pd->iccl, pd->icch); pd->iccl, pd->icch);
...@@ -298,35 +272,43 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) ...@@ -298,35 +272,43 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
return 0; 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 */ unsigned long i2c_clk_khz;
pm_runtime_get_sync(pd->dev); u32 tHIGH, tLOW, tf;
clk_prepare_enable(pd->clk);
/* Enable channel and configure rx ack */ i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count;
iic_set_clr(pd, ICCR, ICCR_ICE, 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;
}
/* Mask all interrupts */ pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
iic_wr(pd, ICIC, 0); pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
/* Set the clock */ return sh_mobile_i2c_check_timing(pd);
iic_wr(pd, ICCL, pd->iccl & 0xff);
iic_wr(pd, ICCH, pd->icch & 0xff);
} }
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 */ unsigned long clks_per_cycle;
iic_wr(pd, ICSR, 0);
iic_wr(pd, ICIC, 0);
/* Disable channel */ /* L = 5, H = 4, L + H = 9 */
iic_set_clr(pd, ICCR, 0, ICCR_ICE); 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 */ return sh_mobile_i2c_check_timing(pd);
clk_disable_unprepare(pd->clk);
pm_runtime_put_sync(pd->dev);
} }
static unsigned char i2c_op(struct sh_mobile_i2c_data *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, ...@@ -350,10 +332,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
case OP_TX: /* write data */ case OP_TX: /* write data */
iic_wr(pd, ICDR, data); iic_wr(pd, ICDR, data);
break; break;
case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */ case OP_TX_STOP: /* issue a stop (or rep_start) */
iic_wr(pd, ICDR, data);
/* fallthrough */
case OP_TX_STOP: /* issue a stop */
iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
: ICCR_ICE | ICCR_TRS | ICCR_BBSY); : ICCR_ICE | ICCR_TRS | ICCR_BBSY);
break; break;
...@@ -387,11 +366,6 @@ static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd) ...@@ -387,11 +366,6 @@ static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
return pd->pos == -1; 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, static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
unsigned char *buf) unsigned char *buf)
{ {
...@@ -409,20 +383,12 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) ...@@ -409,20 +383,12 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
unsigned char data; unsigned char data;
if (pd->pos == pd->msg->len) { 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; return 1;
} }
sh_mobile_i2c_get_data(pd, &data); sh_mobile_i2c_get_data(pd, &data);
i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, 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);
pd->pos++; pd->pos++;
return 0; return 0;
...@@ -464,8 +430,9 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) ...@@ -464,8 +430,9 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
break; break;
} }
data = i2c_op(pd, OP_RX_STOP_DATA, 0); data = i2c_op(pd, OP_RX_STOP_DATA, 0);
} else } else if (real_pos >= 0) {
data = i2c_op(pd, OP_RX, 0); data = i2c_op(pd, OP_RX, 0);
}
if (real_pos >= 0) if (real_pos >= 0)
pd->msg->buf[real_pos] = data; pd->msg->buf[real_pos] = data;
...@@ -548,6 +515,8 @@ static void sh_mobile_i2c_dma_callback(void *data) ...@@ -548,6 +515,8 @@ static void sh_mobile_i2c_dma_callback(void *data)
pd->pos = pd->msg->len; pd->pos = pd->msg->len;
pd->stop_after_dma = true; 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); 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) ...@@ -608,7 +577,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
if (IS_ERR(chan)) if (IS_ERR(chan))
return; 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)) { if (dma_mapping_error(chan->device->dev, dma_addr)) {
dev_dbg(pd->dev, "dma map failed, using PIO\n"); dev_dbg(pd->dev, "dma map failed, using PIO\n");
return; return;
...@@ -651,10 +620,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, ...@@ -651,10 +620,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
if (do_init) { if (do_init) {
/* Initialize channel registers */ /* Initialize channel registers */
iic_set_clr(pd, ICCR, 0, ICCR_ICE); iic_wr(pd, ICCR, ICCR_SCP);
/* Enable channel and configure rx ack */ /* 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 */ /* Set the clock */
iic_wr(pd, ICCL, pd->iccl & 0xff); 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, ...@@ -665,7 +634,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
pd->pos = -1; pd->pos = -1;
pd->sr = 0; 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); sh_mobile_i2c_xfer_dma(pd);
/* Enable all interrupts to begin with */ /* Enable all interrupts to begin with */
...@@ -731,7 +701,8 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, ...@@ -731,7 +701,8 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
int i; int i;
long timeout; long timeout;
activate_ch(pd); /* Wake up device and enable clock */
pm_runtime_get_sync(pd->dev);
/* Process all messages */ /* Process all messages */
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
...@@ -768,11 +739,13 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, ...@@ -768,11 +739,13 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
break; break;
} }
deactivate_ch(pd); /* Disable channel */
iic_wr(pd, ICCR, ICCR_SCP);
/* Disable clock and mark device as idle */
pm_runtime_put_sync(pd->dev);
if (!err) return err ?: num;
err = num;
return err;
} }
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
...@@ -789,7 +762,7 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = { ...@@ -789,7 +762,7 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
* r8a7740 chip has lasting errata on I2C I/O pad reset. * r8a7740 chip has lasting errata on I2C I/O pad reset.
* this is work-around for it. * 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_set_clr(pd, ICCR, ICCR_ICE, 0);
iic_rd(pd, ICCR); /* dummy read */ iic_rd(pd, ICCR); /* dummy read */
...@@ -810,14 +783,23 @@ static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) ...@@ -810,14 +783,23 @@ static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
udelay(10); udelay(10);
iic_wr(pd, ICCR, ICCR_TRS); iic_wr(pd, ICCR, ICCR_TRS);
udelay(10); udelay(10);
return sh_mobile_i2c_init(pd);
} }
static const struct sh_mobile_dt_config default_dt_config = { static const struct sh_mobile_dt_config default_dt_config = {
.clks_per_count = 1, .clks_per_count = 1,
.setup = sh_mobile_i2c_init,
}; };
static const struct sh_mobile_dt_config fast_clock_dt_config = { static const struct sh_mobile_dt_config fast_clock_dt_config = {
.clks_per_count = 2, .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 = { static const struct sh_mobile_dt_config r8a7740_dt_config = {
...@@ -828,7 +810,7 @@ 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[] = { static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config }, { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
{ .compatible = "renesas,iic-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-r8a7791", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
...@@ -910,32 +892,13 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ...@@ -910,32 +892,13 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return PTR_ERR(pd->reg); return PTR_ERR(pd->reg);
ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed); 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; pd->clks_per_count = 1;
config = of_device_get_match_data(&dev->dev); /* Newer variants come with two new bits in ICIC */
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.
*/
if (resource_size(res) > 0x17) if (resource_size(res) > 0x17)
pd->flags |= IIC_FLAG_HAS_ICIC67; 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. /* Enable Runtime PM for this device.
* *
* Also tell the Runtime PM core to ignore children * Also tell the Runtime PM core to ignore children
...@@ -948,6 +911,24 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ...@@ -948,6 +911,24 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
*/ */
pm_suspend_ignore_children(&dev->dev, true); pm_suspend_ignore_children(&dev->dev, true);
pm_runtime_enable(&dev->dev); 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 */ /* setup the private data */
adap = &pd->adap; adap = &pd->adap;
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-smbus.h> #include <linux/i2c-smbus.h>
#include <linux/idr.h> #include <linux/idr.h>
...@@ -134,52 +134,22 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) ...@@ -134,52 +134,22 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
/* i2c bus recovery routines */ /* i2c bus recovery routines */
static int get_scl_gpio_value(struct i2c_adapter *adap) 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) 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) 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; gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val);
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);
} }
/* /*
...@@ -190,7 +160,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) ...@@ -190,7 +160,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap)
#define RECOVERY_NDELAY 5000 #define RECOVERY_NDELAY 5000
#define RECOVERY_CLK_CNT 9 #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; struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
int i = 0, val = 1, ret = 0; int i = 0, val = 1, ret = 0;
...@@ -199,6 +169,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ...@@ -199,6 +169,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
bri->prepare_recovery(adap); bri->prepare_recovery(adap);
bri->set_scl(adap, val); bri->set_scl(adap, val);
if (bri->set_sda)
bri->set_sda(adap, 1);
ndelay(RECOVERY_NDELAY); ndelay(RECOVERY_NDELAY);
/* /*
...@@ -227,33 +199,25 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ...@@ -227,33 +199,25 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
if (bri->get_sda && !bri->get_sda(adap)) if (bri->get_sda && !bri->get_sda(adap))
ret = -EBUSY; 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) if (bri->unprepare_recovery)
bri->unprepare_recovery(adap); bri->unprepare_recovery(adap);
return ret; return ret;
} }
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
return i2c_generic_recovery(adap);
}
EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); 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) int i2c_recover_bus(struct i2c_adapter *adap)
{ {
if (!adap->bus_recovery_info) if (!adap->bus_recovery_info)
...@@ -277,21 +241,19 @@ static void i2c_init_recovery(struct i2c_adapter *adap) ...@@ -277,21 +241,19 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
goto err; goto err;
} }
/* Generic GPIO recovery */ if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_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;
bri->get_scl = get_scl_gpio_value; bri->get_scl = get_scl_gpio_value;
bri->set_scl = set_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 */ /* Generic SCL recovery */
if (!bri->set_scl || !bri->get_scl) { if (!bri->set_scl || !bri->get_scl) {
err_str = "no {get|set}_scl() found"; err_str = "no {get|set}_scl() found";
...@@ -1976,63 +1938,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -1976,63 +1938,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
EXPORT_SYMBOL(i2c_transfer); EXPORT_SYMBOL(i2c_transfer);
/** /**
* i2c_master_send - issue a single I2C message in master transmit mode * i2c_transfer_buffer_flags - issue a single I2C message transferring data
* @client: Handle to slave device * to/from a buffer
* @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
* @client: Handle to slave device * @client: Handle to slave device
* @buf: Where to store data read from slave * @buf: Where the data is stored
* @count: How many bytes to read, must be less than 64k since msg.len is u16 * @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; int ret;
struct i2c_msg msg = {
.addr = client->addr,
.flags = flags | (client->flags & I2C_M_TEN),
.len = count,
.buf = buf,
};
msg.addr = client->addr; ret = i2c_transfer(client->adapter, &msg, 1);
msg.flags = client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = buf;
ret = i2c_transfer(adap, &msg, 1);
/* /*
* If everything went ok (i.e. 1 msg received), return #bytes received, * If everything went ok (i.e. 1 msg transferred), return #bytes
* else error code. * transferred, else error code.
*/ */
return (ret == 1) ? count : ret; return (ret == 1) ? count : ret;
} }
EXPORT_SYMBOL(i2c_master_recv); EXPORT_SYMBOL(i2c_transfer_buffer_flags);
/* ---------------------------------------------------- /* ----------------------------------------------------
* the i2c address scanning function * the i2c address scanning function
...@@ -2265,6 +2199,52 @@ void i2c_put_adapter(struct i2c_adapter *adap) ...@@ -2265,6 +2199,52 @@ void i2c_put_adapter(struct i2c_adapter *adap)
} }
EXPORT_SYMBOL(i2c_put_adapter); 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_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_DESCRIPTION("I2C-Bus main module");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-smbus.h> #include <linux/i2c-smbus.h>
#include <linux/slab.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/smbus.h> #include <trace/events/smbus.h>
...@@ -291,6 +292,22 @@ s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, ...@@ -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); 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 /* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */ No checking of parameters is done! */
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, 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, ...@@ -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].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by msg[1].len = 1; /* block length will be added by
the underlying bus driver */ the underlying bus driver */
i2c_smbus_try_get_dmabuf(&msg[1], 0);
} else { } else {
msg[0].len = data->block[0] + 2; msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 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, ...@@ -376,8 +394,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
data->block[0]); data->block[0]);
return -EINVAL; return -EINVAL;
} }
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++) for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1]; msg[0].buf[i] = data->block[i - 1];
} }
break; break;
case I2C_SMBUS_BLOCK_PROC_CALL: case I2C_SMBUS_BLOCK_PROC_CALL:
...@@ -389,12 +409,16 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, ...@@ -389,12 +409,16 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
data->block[0]); data->block[0]);
return -EINVAL; return -EINVAL;
} }
msg[0].len = data->block[0] + 2; msg[0].len = data->block[0] + 2;
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++) 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].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by msg[1].len = 1; /* block length will be added by
the underlying bus driver */ the underlying bus driver */
i2c_smbus_try_get_dmabuf(&msg[1], 0);
break; break;
case I2C_SMBUS_I2C_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
...@@ -406,10 +430,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, ...@@ -406,10 +430,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
if (read_write == I2C_SMBUS_READ) { if (read_write == I2C_SMBUS_READ) {
msg[1].len = data->block[0]; msg[1].len = data->block[0];
i2c_smbus_try_get_dmabuf(&msg[1], 0);
} else { } else {
msg[0].len = data->block[0] + 1; msg[0].len = data->block[0] + 1;
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i <= data->block[0]; i++) for (i = 1; i <= data->block[0]; i++)
msgbuf0[i] = data->block[i]; msg[0].buf[i] = data->block[i];
} }
break; break;
default: default:
...@@ -457,14 +484,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, ...@@ -457,14 +484,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
break; break;
case I2C_SMBUS_I2C_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < data->block[0]; i++) for (i = 0; i < data->block[0]; i++)
data->block[i+1] = msgbuf1[i]; data->block[i + 1] = msg[1].buf[i];
break; break;
case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL: case I2C_SMBUS_BLOCK_PROC_CALL:
for (i = 0; i < msgbuf1[0] + 1; i++) for (i = 0; i < msg[1].buf[0] + 1; i++)
data->block[i] = msgbuf1[i]; data->block[i] = msg[1].buf[i];
break; 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; return 0;
} }
......
...@@ -264,6 +264,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, ...@@ -264,6 +264,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
res = PTR_ERR(msgs[i].buf); res = PTR_ERR(msgs[i].buf);
break; 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 * If the message length is received from the slave (similar
......
...@@ -64,11 +64,11 @@ config I2C_MUX_PCA9541 ...@@ -64,11 +64,11 @@ config I2C_MUX_PCA9541
will be called i2c-mux-pca9541. will be called i2c-mux-pca9541.
config I2C_MUX_PCA954x config I2C_MUX_PCA954x
tristate "Philips PCA954x I2C Mux/switches" tristate "NXP PCA954x and PCA984x I2C Mux/switches"
depends on GPIOLIB || COMPILE_TEST depends on GPIOLIB || COMPILE_TEST
help help
If you say yes here you get support for the Philips PCA954x If you say yes here you get support for the NXP PCA954x
I2C mux/switch devices. and PCA984x I2C mux/switch devices.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-mux-pca954x. will be called i2c-mux-pca954x.
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it> * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it> * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
* *
* This module supports the PCA954x series of I2C multiplexer/switch chips * This module supports the PCA954x and PCA954x series of I2C multiplexer/switch
* made by Philips Semiconductors. * chips made by NXP Semiconductors.
* This includes the: * This includes the:
* PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547 * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547,
* and PCA9548. * PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849.
* *
* These chips are all controlled via the I2C bus itself, and all have a * 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, * single 8-bit register. The upstream "parent" bus fans out to two,
...@@ -63,6 +63,10 @@ enum pca_type { ...@@ -63,6 +63,10 @@ enum pca_type {
pca_9546, pca_9546,
pca_9547, pca_9547,
pca_9548, pca_9548,
pca_9846,
pca_9847,
pca_9848,
pca_9849,
}; };
struct chip_desc { struct chip_desc {
...@@ -129,6 +133,24 @@ static const struct chip_desc chips[] = { ...@@ -129,6 +133,24 @@ static const struct chip_desc chips[] = {
.nchans = 8, .nchans = 8,
.muxtype = pca954x_isswi, .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[] = { static const struct i2c_device_id pca954x_id[] = {
...@@ -140,6 +162,10 @@ static const struct i2c_device_id pca954x_id[] = { ...@@ -140,6 +162,10 @@ static const struct i2c_device_id pca954x_id[] = {
{ "pca9546", pca_9546 }, { "pca9546", pca_9546 },
{ "pca9547", pca_9547 }, { "pca9547", pca_9547 },
{ "pca9548", pca_9548 }, { "pca9548", pca_9548 },
{ "pca9846", pca_9846 },
{ "pca9847", pca_9847 },
{ "pca9848", pca_9848 },
{ "pca9849", pca_9849 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, pca954x_id); MODULE_DEVICE_TABLE(i2c, pca954x_id);
...@@ -154,6 +180,10 @@ static const struct of_device_id pca954x_of_match[] = { ...@@ -154,6 +180,10 @@ static const struct of_device_id pca954x_of_match[] = {
{ .compatible = "nxp,pca9546", .data = &chips[pca_9546] }, { .compatible = "nxp,pca9546", .data = &chips[pca_9546] },
{ .compatible = "nxp,pca9547", .data = &chips[pca_9547] }, { .compatible = "nxp,pca9547", .data = &chips[pca_9547] },
{ .compatible = "nxp,pca9548", .data = &chips[pca_9548] }, { .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); MODULE_DEVICE_TABLE(of, pca954x_of_match);
......
...@@ -177,6 +177,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) ...@@ -177,6 +177,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
sizeof(mux->data)); sizeof(mux->data));
} else { } else {
ret = i2c_mux_reg_probe_dt(mux, pdev); ret = i2c_mux_reg_probe_dt(mux, pdev);
if (ret == -EPROBE_DEFER)
return ret;
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Error parsing device tree"); dev_err(&pdev->dev, "Error parsing device tree");
return ret; return ret;
......
...@@ -4,6 +4,7 @@ config EEPROM_AT24 ...@@ -4,6 +4,7 @@ config EEPROM_AT24
tristate "I2C EEPROMs / RAMs / ROMs from most vendors" tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
depends on I2C && SYSFS depends on I2C && SYSFS
select NVMEM select NVMEM
select REGMAP_I2C
help help
Enable this driver to get read/write support to most I2C EEPROMs Enable this driver to get read/write support to most I2C EEPROMs
and compatible devices like FRAMs, SRAMs, ROMs etc. After you and compatible devices like FRAMs, SRAMs, ROMs etc. After you
......
...@@ -24,8 +24,10 @@ ...@@ -24,8 +24,10 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/nvmem-provider.h> #include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/platform_data/at24.h> #include <linux/platform_data/at24.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>
/* /*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
...@@ -55,14 +57,13 @@ ...@@ -55,14 +57,13 @@
* which won't work on pure SMBus systems. * which won't work on pure SMBus systems.
*/ */
struct at24_client {
struct i2c_client *client;
struct regmap *regmap;
};
struct at24_data { struct at24_data {
struct at24_platform_data chip; 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, * Lock protects against activities from other Linux tasks,
...@@ -70,18 +71,20 @@ struct at24_data { ...@@ -70,18 +71,20 @@ struct at24_data {
*/ */
struct mutex lock; struct mutex lock;
u8 *writebuf; unsigned int write_max;
unsigned write_max; unsigned int num_addresses;
unsigned num_addresses; unsigned int offset_adj;
struct nvmem_config nvmem_config; struct nvmem_config nvmem_config;
struct nvmem_device *nvmem; struct nvmem_device *nvmem;
struct gpio_desc *wp_gpio;
/* /*
* Some chips tie up multiple I2C addresses; dummy devices reserve * Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us, and we'll use them with SMBus calls. * 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 { ...@@ -93,27 +96,17 @@ struct at24_data {
* *
* This value is forced to be a power of two so that writes align on pages. * This value is forced to be a power of two so that writes align on pages.
*/ */
static unsigned io_limit = 128; static unsigned int at24_io_limit = 128;
module_param(io_limit, uint, 0); module_param_named(io_limit, at24_io_limit, uint, 0);
MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)"); 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; * Specs often allow 5 msec for a page write, sometimes 20 msec;
* it's important to recover from write timeouts. * it's important to recover from write timeouts.
*/ */
static unsigned write_timeout = 25; static unsigned int at24_write_timeout = 25;
module_param(write_timeout, uint, 0); module_param_named(write_timeout, at24_write_timeout, uint, 0);
MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); MODULE_PARM_DESC(at24_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))
/* /*
* Both reads and writes fail if the previous write didn't complete yet. This * 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)"); ...@@ -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 * iteration of processing the request. Both should be unsigned integers
* holding at least 32 bits. * holding at least 32 bits.
*/ */
#define loop_until_timeout(tout, op_time) \ #define at24_loop_until_timeout(tout, op_time) \
for (tout = jiffies + msecs_to_jiffies(write_timeout), op_time = 0; \ for (tout = jiffies + msecs_to_jiffies(at24_write_timeout), \
op_time = 0; \
op_time ? time_before(op_time, tout) : true; \ op_time ? time_before(op_time, tout) : true; \
usleep_range(1000, 1500), op_time = jiffies) 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[] = { static const struct i2c_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */ { "24c00", (kernel_ulong_t)&at24_data_24c00 },
{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) }, { "24c01", (kernel_ulong_t)&at24_data_24c01 },
/* old variants can't be handled with this generic entry! */ { "24cs01", (kernel_ulong_t)&at24_data_24cs01 },
{ "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) }, { "24c02", (kernel_ulong_t)&at24_data_24c02 },
{ "24cs01", AT24_DEVICE_MAGIC(16, { "24cs02", (kernel_ulong_t)&at24_data_24cs02 },
AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, { "24mac402", (kernel_ulong_t)&at24_data_24mac402 },
{ "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, { "24mac602", (kernel_ulong_t)&at24_data_24mac602 },
{ "24cs02", AT24_DEVICE_MAGIC(16, { "spd", (kernel_ulong_t)&at24_data_spd },
AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, { "24c04", (kernel_ulong_t)&at24_data_24c04 },
{ "24mac402", AT24_DEVICE_MAGIC(48 / 8, { "24cs04", (kernel_ulong_t)&at24_data_24cs04 },
AT24_FLAG_MAC | AT24_FLAG_READONLY) }, { "24c08", (kernel_ulong_t)&at24_data_24c08 },
{ "24mac602", AT24_DEVICE_MAGIC(64 / 8, { "24cs08", (kernel_ulong_t)&at24_data_24cs08 },
AT24_FLAG_MAC | AT24_FLAG_READONLY) }, { "24c16", (kernel_ulong_t)&at24_data_24c16 },
/* spd is a 24c02 in memory DIMMs */ { "24cs16", (kernel_ulong_t)&at24_data_24cs16 },
{ "spd", AT24_DEVICE_MAGIC(2048 / 8, { "24c32", (kernel_ulong_t)&at24_data_24c32 },
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, { "24cs32", (kernel_ulong_t)&at24_data_24cs32 },
{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, { "24c64", (kernel_ulong_t)&at24_data_24c64 },
{ "24cs04", AT24_DEVICE_MAGIC(16, { "24cs64", (kernel_ulong_t)&at24_data_24cs64 },
AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, { "24c128", (kernel_ulong_t)&at24_data_24c128 },
/* 24rf08 quirk is handled at i2c-core */ { "24c256", (kernel_ulong_t)&at24_data_24c256 },
{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, { "24c512", (kernel_ulong_t)&at24_data_24c512 },
{ "24cs08", AT24_DEVICE_MAGIC(16, { "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
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 }, { "at24", 0 },
{ /* END OF LIST */ } { /* END OF LIST */ }
}; };
MODULE_DEVICE_TABLE(i2c, at24_ids); MODULE_DEVICE_TABLE(i2c, at24_ids);
static const struct of_device_id at24_of_match[] = { static const struct of_device_id at24_of_match[] = {
{ { .compatible = "atmel,24c00", .data = &at24_data_24c00 },
.compatible = "atmel,24c00", { .compatible = "atmel,24c01", .data = &at24_data_24c01 },
.data = (void *)AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) { .compatible = "atmel,24cs01", .data = &at24_data_24cs01 },
}, { .compatible = "atmel,24c02", .data = &at24_data_24c02 },
{ { .compatible = "atmel,24cs02", .data = &at24_data_24cs02 },
.compatible = "atmel,24c01", { .compatible = "atmel,24mac402", .data = &at24_data_24mac402 },
.data = (void *)AT24_DEVICE_MAGIC(1024 / 8, 0) { .compatible = "atmel,24mac602", .data = &at24_data_24mac602 },
}, { .compatible = "atmel,spd", .data = &at24_data_spd },
{ { .compatible = "atmel,24c04", .data = &at24_data_24c04 },
.compatible = "atmel,24c02", { .compatible = "atmel,24cs04", .data = &at24_data_24cs04 },
.data = (void *)AT24_DEVICE_MAGIC(2048 / 8, 0) { .compatible = "atmel,24c08", .data = &at24_data_24c08 },
}, { .compatible = "atmel,24cs08", .data = &at24_data_24cs08 },
{ { .compatible = "atmel,24c16", .data = &at24_data_24c16 },
.compatible = "atmel,spd", { .compatible = "atmel,24cs16", .data = &at24_data_24cs16 },
.data = (void *)AT24_DEVICE_MAGIC(2048 / 8, { .compatible = "atmel,24c32", .data = &at24_data_24c32 },
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) { .compatible = "atmel,24cs32", .data = &at24_data_24cs32 },
}, { .compatible = "atmel,24c64", .data = &at24_data_24c64 },
{ { .compatible = "atmel,24cs64", .data = &at24_data_24cs64 },
.compatible = "atmel,24c04", { .compatible = "atmel,24c128", .data = &at24_data_24c128 },
.data = (void *)AT24_DEVICE_MAGIC(4096 / 8, 0) { .compatible = "atmel,24c256", .data = &at24_data_24c256 },
}, { .compatible = "atmel,24c512", .data = &at24_data_24c512 },
{ { .compatible = "atmel,24c1024", .data = &at24_data_24c1024 },
.compatible = "atmel,24c08", { /* END OF LIST */ },
.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)
},
{ },
}; };
MODULE_DEVICE_TABLE(of, at24_of_match); MODULE_DEVICE_TABLE(of, at24_of_match);
static const struct acpi_device_id at24_acpi_ids[] = { 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); MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
...@@ -251,20 +249,11 @@ 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 * Slave address and byte offset derive from the offset. Always
* set the byte address; on a multi-master board, another master * set the byte address; on a multi-master board, another master
* may have changed the chip's "current" address pointer. * 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, static struct at24_client *at24_translate_offset(struct at24_data *at24,
unsigned int *offset) unsigned int *offset)
{ {
unsigned i; unsigned int i;
if (at24->chip.flags & AT24_FLAG_ADDR16) { if (at24->chip.flags & AT24_FLAG_ADDR16) {
i = *offset >> 16; i = *offset >> 16;
...@@ -274,168 +263,55 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24, ...@@ -274,168 +263,55 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24,
*offset &= 0xff; *offset &= 0xff;
} }
return at24->client[i]; return &at24->client[i];
}
static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
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;
/*
* 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.
*/
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;
}
return -ETIMEDOUT;
} }
static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf, static size_t at24_adjust_read_count(struct at24_data *at24,
unsigned int offset, size_t count) unsigned int offset, size_t count)
{ {
unsigned long timeout, read_time; unsigned int bits;
struct i2c_client *client; size_t remainder;
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, * In case of multi-address chips that don't rollover reads to
* regardless of the intended address. * the next slave address: truncate the count to the slave boundary,
* so that the read never straddles slaves.
*/ */
addrbuf[0] = 0x80 + offset; if (at24->chip.flags & AT24_FLAG_NO_RDROL) {
msg[0].len = 1; bits = (at24->chip.flags & AT24_FLAG_ADDR16) ? 16 : 8;
remainder = BIT(bits) - offset;
if (count > remainder)
count = remainder;
} }
msg[1].addr = client->addr; if (count > at24_io_limit)
msg[1].flags = I2C_M_RD; count = at24_io_limit;
msg[1].buf = buf;
msg[1].len = count;
loop_until_timeout(timeout, read_time) {
status = i2c_transfer(client->adapter, msg, 2);
if (status == 2)
return count; return count;
}
return -ETIMEDOUT;
} }
static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf, static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
unsigned int offset, size_t count) unsigned int offset, size_t count)
{ {
unsigned long timeout, read_time; unsigned long timeout, read_time;
struct at24_client *at24_client;
struct i2c_client *client; struct i2c_client *client;
struct i2c_msg msg[2]; struct regmap *regmap;
u8 addrbuf[2]; int ret;
int status;
client = at24_translate_offset(at24, &offset); at24_client = at24_translate_offset(at24, &offset);
regmap = at24_client->regmap;
client = at24_client->client;
count = at24_adjust_read_count(at24, offset, count);
memset(msg, 0, sizeof(msg)); /* adjust offset for mac and serial read ops */
msg[0].addr = client->addr; offset += at24->offset_adj;
msg[0].buf = addrbuf;
/* EUI-48 starts from 0x9a, EUI-64 from 0x98 */ at24_loop_until_timeout(timeout, read_time) {
addrbuf[0] = 0xa0 - at24->chip.byte_len + offset; ret = regmap_bulk_read(regmap, offset, buf, count);
msg[0].len = 1; dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
msg[1].addr = client->addr; count, offset, ret, jiffies);
msg[1].flags = I2C_M_RD; if (!ret)
msg[1].buf = buf;
msg[1].len = count;
loop_until_timeout(timeout, read_time) {
status = i2c_transfer(client->adapter, msg, 2);
if (status == 2)
return count; return count;
} }
...@@ -454,7 +330,7 @@ static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf, ...@@ -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, static size_t at24_adjust_write_count(struct at24_data *at24,
unsigned int offset, size_t count) unsigned int offset, size_t count)
{ {
unsigned next_page; unsigned int next_page;
/* write_max is at most a page */ /* write_max is at most a page */
if (count > at24->write_max) if (count > at24->write_max)
...@@ -468,91 +344,25 @@ static size_t at24_adjust_write_count(struct at24_data *at24, ...@@ -468,91 +344,25 @@ static size_t at24_adjust_write_count(struct at24_data *at24,
return count; return count;
} }
static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24, static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
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);
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 int offset, size_t count)
{ {
unsigned long timeout, write_time; unsigned long timeout, write_time;
struct at24_client *at24_client;
struct i2c_client *client; struct i2c_client *client;
struct i2c_msg msg; struct regmap *regmap;
ssize_t status = 0; int ret;
int i = 0;
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); count = at24_adjust_write_count(at24, offset, count);
msg.addr = client->addr; at24_loop_until_timeout(timeout, write_time) {
msg.flags = 0; ret = regmap_bulk_write(regmap, offset, buf, count);
dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n",
/* msg.buf is u8 and casts will mask the values */ count, offset, ret, jiffies);
msg.buf = at24->writebuf; if (!ret)
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)
return count; return count;
} }
...@@ -562,7 +372,7 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, ...@@ -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) static int at24_read(void *priv, unsigned int off, void *val, size_t count)
{ {
struct at24_data *at24 = priv; struct at24_data *at24 = priv;
struct device *dev = &at24->client[0]->dev; struct device *dev = &at24->client[0].client->dev;
char *buf = val; char *buf = val;
int ret; int ret;
...@@ -587,7 +397,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) ...@@ -587,7 +397,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
while (count) { while (count) {
int status; int status;
status = at24->read_func(at24, buf, off, count); status = at24_regmap_read(at24, buf, off, count);
if (status < 0) { if (status < 0) {
mutex_unlock(&at24->lock); mutex_unlock(&at24->lock);
pm_runtime_put(dev); pm_runtime_put(dev);
...@@ -608,7 +418,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) ...@@ -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) static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{ {
struct at24_data *at24 = priv; struct at24_data *at24 = priv;
struct device *dev = &at24->client[0]->dev; struct device *dev = &at24->client[0].client->dev;
char *buf = val; char *buf = val;
int ret; int ret;
...@@ -629,12 +439,14 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) ...@@ -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. * from this host, but not from other I2C masters.
*/ */
mutex_lock(&at24->lock); mutex_lock(&at24->lock);
gpiod_set_value_cansleep(at24->wp_gpio, 0);
while (count) { while (count) {
int status; int status;
status = at24->write_func(at24, buf, off, count); status = at24_regmap_write(at24, buf, off, count);
if (status < 0) { if (status < 0) {
gpiod_set_value_cansleep(at24->wp_gpio, 1);
mutex_unlock(&at24->lock); mutex_unlock(&at24->lock);
pm_runtime_put(dev); pm_runtime_put(dev);
return status; return status;
...@@ -644,6 +456,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) ...@@ -644,6 +456,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
count -= status; count -= status;
} }
gpiod_set_value_cansleep(at24->wp_gpio, 1);
mutex_unlock(&at24->lock); mutex_unlock(&at24->lock);
pm_runtime_put(dev); pm_runtime_put(dev);
...@@ -658,6 +471,8 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) ...@@ -658,6 +471,8 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
if (device_property_present(dev, "read-only")) if (device_property_present(dev, "read-only"))
chip->flags |= AT24_FLAG_READONLY; 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); err = device_property_read_u32(dev, "size", &val);
if (!err) if (!err)
...@@ -676,16 +491,38 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) ...@@ -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) static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ {
struct at24_platform_data chip; struct at24_platform_data chip = { 0 };
kernel_ulong_t magic = 0; const struct at24_chip_data *cd = NULL;
bool writable; bool writable;
int use_smbus = 0;
int use_smbus_write = 0;
struct at24_data *at24; struct at24_data *at24;
int err; int err;
unsigned i, num_addresses; unsigned int i, num_addresses;
struct regmap_config regmap_config = { };
u8 test_byte; u8 test_byte;
if (client->dev.platform_data) { if (client->dev.platform_data) {
...@@ -698,28 +535,22 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -698,28 +535,22 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/ */
if (client->dev.of_node && if (client->dev.of_node &&
of_match_device(at24_of_match, &client->dev)) { of_match_device(at24_of_match, &client->dev)) {
magic = (kernel_ulong_t) cd = of_device_get_match_data(&client->dev);
of_device_get_match_data(&client->dev);
} else if (id) { } else if (id) {
magic = id->driver_data; cd = (void *)id->driver_data;
} else { } else {
const struct acpi_device_id *aid; const struct acpi_device_id *aid;
aid = acpi_match_device(at24_acpi_ids, &client->dev); aid = acpi_match_device(at24_acpi_ids, &client->dev);
if (aid) if (aid)
magic = aid->driver_data; cd = (void *)aid->driver_data;
} }
if (!magic) if (!cd)
return -ENODEV; return -ENODEV;
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN)); chip.byte_len = cd->byte_len;
magic >>= AT24_SIZE_BYTELEN; chip.flags = cd->flags;
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
at24_get_pdata(&client->dev, &chip); at24_get_pdata(&client->dev, &chip);
chip.setup = NULL;
chip.context = NULL;
} }
if (!is_power_of_2(chip.byte_len)) 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) ...@@ -733,43 +564,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_warn(&client->dev, dev_warn(&client->dev,
"page_size looks suspicious (no power of 2)!\n"); "page_size looks suspicious (no power of 2)!\n");
/* if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
* REVISIT: the size of the EUI-48 byte array is 6 in at24mac402, while !i2c_check_functionality(client->adapter,
* the call to ilog2() in AT24_DEVICE_MAGIC() rounds it down to 4. I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
*
* 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; chip.page_size = 1;
}
}
if (chip.flags & AT24_FLAG_TAKE8ADDR) if (chip.flags & AT24_FLAG_TAKE8ADDR)
num_addresses = 8; num_addresses = 8;
...@@ -777,16 +575,28 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -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, num_addresses = DIV_ROUND_UP(chip.byte_len,
(chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256); (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) + 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) if (!at24)
return -ENOMEM; return -ENOMEM;
mutex_init(&at24->lock); mutex_init(&at24->lock);
at24->use_smbus = use_smbus;
at24->use_smbus_write = use_smbus_write;
at24->chip = chip; at24->chip = chip;
at24->num_addresses = num_addresses; 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)) { if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) {
dev_err(&client->dev, dev_err(&client->dev,
...@@ -794,59 +604,32 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -794,59 +604,32 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -EINVAL; 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); writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) { if (writable) {
if (!use_smbus || use_smbus_write) { at24->write_max = min_t(unsigned int,
chip.page_size, at24_io_limit);
unsigned write_max = chip.page_size; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
at24->write_max > I2C_SMBUS_BLOCK_MAX)
if (write_max > io_limit) at24->write_max = I2C_SMBUS_BLOCK_MAX;
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->client[0] = client;
/* use dummy devices for multiple-address chips */ /* use dummy devices for multiple-address chips */
for (i = 1; i < num_addresses; i++) { for (i = 1; i < num_addresses; i++) {
at24->client[i] = i2c_new_dummy(client->adapter, at24->client[i].client = i2c_new_dummy(client->adapter,
client->addr + i); client->addr + i);
if (!at24->client[i]) { if (!at24->client[i].client) {
dev_err(&client->dev, "address 0x%02x unavailable\n", dev_err(&client->dev, "address 0x%02x unavailable\n",
client->addr + i); client->addr + i);
err = -EADDRINUSE; err = -EADDRINUSE;
goto err_clients; 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); i2c_set_clientdata(client, at24);
...@@ -890,12 +673,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -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", dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
chip.byte_len, client->name, chip.byte_len, client->name,
writable ? "writable" : "read-only", at24->write_max); 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 */ /* export data to kernel code */
if (chip.setup) if (chip.setup)
...@@ -905,8 +682,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -905,8 +682,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
err_clients: err_clients:
for (i = 1; i < num_addresses; i++) for (i = 1; i < num_addresses; i++)
if (at24->client[i]) if (at24->client[i].client)
i2c_unregister_device(at24->client[i]); i2c_unregister_device(at24->client[i].client);
pm_runtime_disable(&client->dev); pm_runtime_disable(&client->dev);
...@@ -923,7 +700,7 @@ static int at24_remove(struct i2c_client *client) ...@@ -923,7 +700,7 @@ static int at24_remove(struct i2c_client *client)
nvmem_unregister(at24->nvmem); nvmem_unregister(at24->nvmem);
for (i = 1; i < at24->num_addresses; i++) 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_disable(&client->dev);
pm_runtime_set_suspended(&client->dev); pm_runtime_set_suspended(&client->dev);
...@@ -946,12 +723,12 @@ static struct i2c_driver at24_driver = { ...@@ -946,12 +723,12 @@ static struct i2c_driver at24_driver = {
static int __init at24_init(void) static int __init at24_init(void)
{ {
if (!io_limit) { if (!at24_io_limit) {
pr_err("at24: io_limit must not be 0!\n"); pr_err("at24: at24_io_limit must not be 0!\n");
return -EINVAL; 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); return i2c_add_driver(&at24_driver);
} }
module_init(at24_init); module_init(at24_init);
......
...@@ -55,7 +55,7 @@ typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *); ...@@ -55,7 +55,7 @@ typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);
struct module; struct module;
struct property_entry; 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 * 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 * on a bus (or read from them). Apart from two basic transfer functions to
...@@ -63,10 +63,68 @@ struct property_entry; ...@@ -63,10 +63,68 @@ struct property_entry;
* transmit an arbitrary number of messages without interruption. * transmit an arbitrary number of messages without interruption.
* @count must be be less than 64k since msg.len is u16. * @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, extern int i2c_transfer_buffer_flags(const struct i2c_client *client,
int count); char *buf, int count, u16 flags);
extern int i2c_master_recv(const struct i2c_client *client, char *buf,
int count); /**
* 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. /* Transfer num messages.
*/ */
...@@ -354,7 +412,7 @@ struct i2c_board_info { ...@@ -354,7 +412,7 @@ struct i2c_board_info {
.type = dev_type, .addr = (dev_addr) .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 /* Add-on boards should register/unregister their devices; e.g. a board
* with integrated I2C, a config eeprom, sensors, and a codec that's * with integrated I2C, a config eeprom, sensors, and a codec that's
* used in conjunction with the primary hardware. * used in conjunction with the primary hardware.
...@@ -485,40 +543,43 @@ struct i2c_timings { ...@@ -485,40 +543,43 @@ struct i2c_timings {
/** /**
* struct i2c_bus_recovery_info - I2C bus recovery information * struct i2c_bus_recovery_info - I2C bus recovery information
* @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or * @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 * @get_scl: This gets current value of 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 SCL line. Mandatory for generic SCL recovery. Used * @set_scl: This sets/clears the SCL line. Mandatory for generic SCL recovery.
* internally for generic GPIO recovery. * Populated internally for generic GPIO recovery.
* @get_sda: This gets current value of SDA line. Optional for generic SCL * @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. 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. * recovery.
* @prepare_recovery: This will be called before starting recovery. Platform may * @prepare_recovery: This will be called before starting recovery. Platform may
* configure padmux here for SDA/SCL line or something else they want. * configure padmux here for SDA/SCL line or something else they want.
* @unprepare_recovery: This will be called after completing recovery. Platform * @unprepare_recovery: This will be called after completing recovery. Platform
* may configure padmux here for SDA/SCL line or something else they want. * 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. * @scl_gpiod: gpiod of the SCL line. Only required for GPIO recovery.
* @sda_gpio: gpio number of the SDA line. Only required for GPIO recovery. * @sda_gpiod: gpiod of the SDA line. Only required for GPIO recovery.
*/ */
struct i2c_bus_recovery_info { struct i2c_bus_recovery_info {
int (*recover_bus)(struct i2c_adapter *); int (*recover_bus)(struct i2c_adapter *adap);
int (*get_scl)(struct i2c_adapter *); int (*get_scl)(struct i2c_adapter *adap);
void (*set_scl)(struct i2c_adapter *, int val); void (*set_scl)(struct i2c_adapter *adap, int val);
int (*get_sda)(struct i2c_adapter *); int (*get_sda)(struct i2c_adapter *adap);
void (*set_sda)(struct i2c_adapter *adap, int val);
void (*prepare_recovery)(struct i2c_adapter *); void (*prepare_recovery)(struct i2c_adapter *adap);
void (*unprepare_recovery)(struct i2c_adapter *); void (*unprepare_recovery)(struct i2c_adapter *adap);
/* gpio recovery */ /* gpio recovery */
int scl_gpio; struct gpio_desc *scl_gpiod;
int sda_gpio; struct gpio_desc *sda_gpiod;
}; };
int i2c_recover_bus(struct i2c_adapter *adap); int i2c_recover_bus(struct i2c_adapter *adap);
/* Generic recovery routines */ /* Generic recovery routines */
int i2c_generic_gpio_recovery(struct i2c_adapter *adap);
int i2c_generic_scl_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) ...@@ -706,7 +767,7 @@ i2c_unlock_adapter(struct i2c_adapter *adapter)
/* administration... /* administration...
*/ */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if IS_ENABLED(CONFIG_I2C)
extern int i2c_add_adapter(struct i2c_adapter *); extern int i2c_add_adapter(struct i2c_adapter *);
extern void i2c_del_adapter(struct i2c_adapter *); extern void i2c_del_adapter(struct i2c_adapter *);
extern int i2c_add_numbered_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) ...@@ -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); 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); int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr);
/** /**
* module_i2c_driver() - Helper macro for registering a modular I2C driver * module_i2c_driver() - Helper macro for registering a modular I2C driver
......
...@@ -50,6 +50,8 @@ struct at24_platform_data { ...@@ -50,6 +50,8 @@ struct at24_platform_data {
#define AT24_FLAG_TAKE8ADDR BIT(4) /* take always 8 addresses (24c00) */ #define AT24_FLAG_TAKE8ADDR BIT(4) /* take always 8 addresses (24c00) */
#define AT24_FLAG_SERIAL BIT(3) /* factory-programmed serial number */ #define AT24_FLAG_SERIAL BIT(3) /* factory-programmed serial number */
#define AT24_FLAG_MAC BIT(2) /* factory-programmed mac address */ #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 (*setup)(struct nvmem_device *nvmem, void *context);
void *context; void *context;
......
...@@ -16,9 +16,8 @@ ...@@ -16,9 +16,8 @@
struct davinci_i2c_platform_data { struct davinci_i2c_platform_data {
unsigned int bus_freq; /* standard bus frequency (kHz) */ unsigned int bus_freq; /* standard bus frequency (kHz) */
unsigned int bus_delay; /* post-transaction delay (usec) */ unsigned int bus_delay; /* post-transaction delay (usec) */
unsigned int sda_pin; /* GPIO pin ID to use for SDA */ bool gpio_recovery; /* Use GPIO recovery method */
unsigned int scl_pin; /* GPIO pin ID to use for SCL */ bool has_pfunc; /* Chip has a ICPFUNC register */
bool has_pfunc; /*chip has a ICPFUNC register */
}; };
/* for board setup code */ /* for board setup code */
......
...@@ -72,6 +72,9 @@ struct i2c_msg { ...@@ -72,6 +72,9 @@ struct i2c_msg {
#define I2C_M_RD 0x0001 /* read data, from slave to master */ #define I2C_M_RD 0x0001 /* read data, from slave to master */
/* I2C_M_RD is guaranteed to be 0x0001! */ /* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ #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_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment