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