mirror of https://gitee.com/openkylin/linux.git
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "Most notable: - introducing the i2c_quirk infrastructure. Now, flaws of I2C controllers can be described and the core will check if the flaws collide with the messages to be sent - wait_for_completion return type cleanup series - new drivers for Digicolor, Netlogic XLP, Ingenic JZ4780 - updates to the I2C slave framework which include API changes. Its only user was updated, too. Documentation was finally added - changed dynamic bus numbering for the DT case. This could change bus numbers for users. However, it fixes a collision where dynamic and static busses request the same id. - driver bugfixes, cleanups" * 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (52 commits) i2c: xlp9xx: Driver for Netlogic XLP9XX/5XX I2C controller of: Add vendor prefix 'netlogic' i2c: davinci: use ICPFUNC to toggle I2C as gpio for bus recovery i2c: davinci: use bus recovery infrastructure i2c: change input parameter to i2c_adapter for prepare/unprepare_recovery i2c: i2c-mux-gpio: remove error messages for probe deferrals i2c: jz4780: Add i2c bus controller driver for Ingenic JZ4780 i2c: dln2: set the device tree node of the adapter i2c: davinci: fixup wait_for_completion_timeout handling i2c: mpc: Fix ISR return value i2c: slave-eeprom: add more info when to increase the pointer i2c: slave: add documentation for i2c-slave-eeprom Documentation: i2c: describe the new slave mode i2c: slave: rework the slave API i2c: add support for the Digicolor I2C controller i2c: busses with dynamic ids should start after fixed ids for DT of: base: add function to get highest id of an alias stem i2c: designware: Suppress error message if platform_get_irq() < 0 i2c: mpc: assign the correct prescaler from SVR i2c: img-scb: fixup of wait_for_completion_timeout return handling ...
This commit is contained in:
commit
c3a416a669
|
@ -10,6 +10,9 @@ Required properties:
|
||||||
Recommended properties :
|
Recommended properties :
|
||||||
- interrupts : standard interrupt property.
|
- interrupts : standard interrupt property.
|
||||||
- clock-frequency : desired I2C bus clock frequency in Hz.
|
- clock-frequency : desired I2C bus clock frequency in Hz.
|
||||||
|
- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC
|
||||||
|
registers. PFUNC registers allow to switch I2C pins to function as
|
||||||
|
GPIOs, so they can by toggled manually.
|
||||||
|
|
||||||
Example (enbw_cmc board):
|
Example (enbw_cmc board):
|
||||||
i2c@1c22000 {
|
i2c@1c22000 {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
Conexant Digicolor I2C controller
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: must be "cnxt,cx92755-i2c"
|
||||||
|
- reg: physical address and length of the device registers
|
||||||
|
- interrupts: a single interrupt specifier
|
||||||
|
- clocks: clock for the device
|
||||||
|
- #address-cells: should be <1>
|
||||||
|
- #size-cells: should be <0>
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- clock-frequency: the desired I2C bus clock frequency in Hz; in
|
||||||
|
absence of this property the default value is used (100 kHz).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
i2c: i2c@f0000120 {
|
||||||
|
compatible = "cnxt,cx92755-i2c";
|
||||||
|
reg = <0xf0000120 0x10>;
|
||||||
|
interrupts = <28>;
|
||||||
|
clocks = <&main_clk>;
|
||||||
|
clock-frequency = <100000>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
* Ingenic JZ4780 I2C Bus controller
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "ingenic,jz4780-i2c"
|
||||||
|
- reg: Should contain the address & size of the I2C controller registers.
|
||||||
|
- interrupts: Should specify the interrupt provided by parent.
|
||||||
|
- clocks: Should contain a single clock specifier for the JZ4780 I2C clock.
|
||||||
|
- clock-frequency: desired I2C bus clock frequency in Hz.
|
||||||
|
|
||||||
|
Recommended properties:
|
||||||
|
- pinctrl-names: should be "default";
|
||||||
|
- pinctrl-0: phandle to pinctrl function
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- interrupt-parent: Should be the phandle of the interrupt controller that
|
||||||
|
delivers interrupts to the I2C block.
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
/ {
|
||||||
|
i2c4: i2c4@0x10054000 {
|
||||||
|
compatible = "ingenic,jz4780-i2c";
|
||||||
|
reg = <0x10054000 0x1000>;
|
||||||
|
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
interrupts = <56>;
|
||||||
|
|
||||||
|
clocks = <&cgu JZ4780_CLK_SMB4>;
|
||||||
|
clock-frequency = <100000>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pins_i2c4_data>;
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
Device tree configuration for the I2C controller on the XLP9xx/5xx SoC
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : should be "netlogic,xlp980-i2c"
|
||||||
|
- reg : bus address start and address range size of device
|
||||||
|
- interrupts : interrupt number
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- clock-frequency : frequency of bus clock in Hz
|
||||||
|
Defaults to 100 KHz when the property is not specified
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
i2c0: i2c@113100 {
|
||||||
|
compatible = "netlogic,xlp980-i2c";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
reg = <0 0x113100 0x100>;
|
||||||
|
clock-frequency = <400000>;
|
||||||
|
interrupts = <30>;
|
||||||
|
interrupt-parent = <&pic>;
|
||||||
|
};
|
|
@ -125,6 +125,7 @@ mxicy Macronix International Co., Ltd.
|
||||||
national National Semiconductor
|
national National Semiconductor
|
||||||
neonode Neonode Inc.
|
neonode Neonode Inc.
|
||||||
netgear NETGEAR
|
netgear NETGEAR
|
||||||
|
netlogic Broadcom Corporation (formerly NetLogic Microsystems)
|
||||||
newhaven Newhaven Display International
|
newhaven Newhaven Display International
|
||||||
nintendo Nintendo
|
nintendo Nintendo
|
||||||
nokia Nokia
|
nokia Nokia
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
Linux I2C slave eeprom backend
|
||||||
|
==============================
|
||||||
|
|
||||||
|
by Wolfram Sang <wsa@sang-engineering.com> in 2014-15
|
||||||
|
|
||||||
|
This is a proof-of-concept backend which acts like an EEPROM on the connected
|
||||||
|
I2C bus. The memory contents can be modified from userspace via this file
|
||||||
|
located in sysfs:
|
||||||
|
|
||||||
|
/sys/bus/i2c/devices/<device-direcory>/slave-eeprom
|
||||||
|
|
||||||
|
As of 2015, Linux doesn't support poll on binary sysfs files, so there is no
|
||||||
|
notfication when another master changed the content.
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
Linux I2C slave interface description
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
by Wolfram Sang <wsa@sang-engineering.com> in 2014-15
|
||||||
|
|
||||||
|
Linux can also be an I2C slave in case I2C controllers have slave support.
|
||||||
|
Besides this HW requirement, one also needs a software backend providing the
|
||||||
|
actual functionality. An example for this is the slave-eeprom driver, which
|
||||||
|
acts as a dual memory driver. While another I2C master on the bus can access it
|
||||||
|
like a regular EEPROM, the Linux I2C slave can access the content via sysfs and
|
||||||
|
retrieve/provide information as needed. The software backend driver and the I2C
|
||||||
|
bus driver communicate via events. Here is a small graph visualizing the data
|
||||||
|
flow and the means by which data is transported. The dotted line marks only one
|
||||||
|
example. The backend could also use e.g. a character device, be in-kernel
|
||||||
|
only, or something completely different:
|
||||||
|
|
||||||
|
|
||||||
|
e.g. sysfs I2C slave events I/O registers
|
||||||
|
+-----------+ v +---------+ v +--------+ v +------------+
|
||||||
|
| Userspace +........+ Backend +-----------+ Driver +-----+ Controller |
|
||||||
|
+-----------+ +---------+ +--------+ +------------+
|
||||||
|
| |
|
||||||
|
----------------------------------------------------------------+-- I2C
|
||||||
|
--------------------------------------------------------------+---- Bus
|
||||||
|
|
||||||
|
Note: Technically, there is also the I2C core between the backend and the
|
||||||
|
driver. However, at this time of writing, the layer is transparent.
|
||||||
|
|
||||||
|
|
||||||
|
User manual
|
||||||
|
===========
|
||||||
|
|
||||||
|
I2C slave backends behave like standard I2C clients. So, you can instantiate
|
||||||
|
them like described in the document 'instantiating-devices'. A quick example
|
||||||
|
for instantiating the slave-eeprom driver from userspace:
|
||||||
|
|
||||||
|
# echo 0-0064 > /sys/bus/i2c/drivers/i2c-slave-eeprom/bind
|
||||||
|
|
||||||
|
Each backend should come with separate documentation to describe its specific
|
||||||
|
behaviour and setup.
|
||||||
|
|
||||||
|
|
||||||
|
Developer manual
|
||||||
|
================
|
||||||
|
|
||||||
|
I2C slave events
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The bus driver sends an event to the backend using the following function:
|
||||||
|
|
||||||
|
ret = i2c_slave_event(client, event, &val)
|
||||||
|
|
||||||
|
'client' describes the i2c slave device. 'event' is one of the special event
|
||||||
|
types described hereafter. 'val' holds an u8 value for the data byte to be
|
||||||
|
read/written and is thus bidirectional. The pointer to val must always be
|
||||||
|
provided even if val is not used for an event, i.e. don't use NULL here. 'ret'
|
||||||
|
is the return value from the backend. Mandatory events must be provided by the
|
||||||
|
bus drivers and must be checked for by backend drivers.
|
||||||
|
|
||||||
|
Event types:
|
||||||
|
|
||||||
|
* I2C_SLAVE_WRITE_REQUESTED (mandatory)
|
||||||
|
|
||||||
|
'val': unused
|
||||||
|
'ret': always 0
|
||||||
|
|
||||||
|
Another I2C master wants to write data to us. This event should be sent once
|
||||||
|
our own address and the write bit was detected. The data did not arrive yet, so
|
||||||
|
there is nothing to process or return. Wakeup or initialization probably needs
|
||||||
|
to be done, though.
|
||||||
|
|
||||||
|
* I2C_SLAVE_READ_REQUESTED (mandatory)
|
||||||
|
|
||||||
|
'val': backend returns first byte to be sent
|
||||||
|
'ret': always 0
|
||||||
|
|
||||||
|
Another I2C master wants to read data from us. This event should be sent once
|
||||||
|
our own address and the read bit was detected. After returning, the bus driver
|
||||||
|
should transmit the first byte.
|
||||||
|
|
||||||
|
* I2C_SLAVE_WRITE_RECEIVED (mandatory)
|
||||||
|
|
||||||
|
'val': bus driver delivers received byte
|
||||||
|
'ret': 0 if the byte should be acked, some errno if the byte should be nacked
|
||||||
|
|
||||||
|
Another I2C master has sent a byte to us which needs to be set in 'val'. If 'ret'
|
||||||
|
is zero, the bus driver should ack this byte. If 'ret' is an errno, then the byte
|
||||||
|
should be nacked.
|
||||||
|
|
||||||
|
* I2C_SLAVE_READ_PROCESSED (mandatory)
|
||||||
|
|
||||||
|
'val': backend returns next byte to be sent
|
||||||
|
'ret': always 0
|
||||||
|
|
||||||
|
The bus driver requests the next byte to be sent to another I2C master in
|
||||||
|
'val'. Important: This does not mean that the previous byte has been acked, it
|
||||||
|
only means that the previous byte is shifted out to the bus! To ensure seamless
|
||||||
|
transmission, most hardware requests the next byte when the previous one is
|
||||||
|
still shifted out. If the master sends NACK and stops reading after the byte
|
||||||
|
currently shifted out, this byte requested here is never used. It very likely
|
||||||
|
needs to be sent again on the next I2C_SLAVE_READ_REQUEST, depending a bit on
|
||||||
|
your backend, though.
|
||||||
|
|
||||||
|
* I2C_SLAVE_STOP (mandatory)
|
||||||
|
|
||||||
|
'val': unused
|
||||||
|
'ret': always 0
|
||||||
|
|
||||||
|
A stop condition was received. This can happen anytime and the backend should
|
||||||
|
reset its state machine for I2C transfers to be able to receive new requests.
|
||||||
|
|
||||||
|
|
||||||
|
Software backends
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
If you want to write a software backend:
|
||||||
|
|
||||||
|
* use a standard i2c_driver and its matching mechanisms
|
||||||
|
* write the slave_callback which handles the above slave events
|
||||||
|
(best using a state machine)
|
||||||
|
* register this callback via i2c_slave_register()
|
||||||
|
|
||||||
|
Check the i2c-slave-eeprom driver as an example.
|
||||||
|
|
||||||
|
|
||||||
|
Bus driver support
|
||||||
|
------------------
|
||||||
|
|
||||||
|
If you want to add slave support to the bus driver:
|
||||||
|
|
||||||
|
* implement calls to register/unregister the slave and add those to the
|
||||||
|
struct i2c_algorithm. When registering, you probably need to set the i2c
|
||||||
|
slave address and enable slave specific interrupts. If you use runtime pm, you
|
||||||
|
should use pm_runtime_forbid() because your device usually needs to be powered
|
||||||
|
on always to be able to detect its slave address. When unregistering, do the
|
||||||
|
inverse of the above.
|
||||||
|
|
||||||
|
* Catch the slave interrupts and send appropriate i2c_slave_events to the backend.
|
||||||
|
|
||||||
|
Check the i2c-rcar driver as an example.
|
||||||
|
|
||||||
|
|
||||||
|
About ACK/NACK
|
||||||
|
--------------
|
||||||
|
|
||||||
|
It is good behaviour to always ACK the address phase, so the master knows if a
|
||||||
|
device is basically present or if it mysteriously disappeared. Using NACK to
|
||||||
|
state being busy is troublesome. SMBus demands to always ACK the address phase,
|
||||||
|
while the I2C specification is more loose on that. Most I2C controllers also
|
||||||
|
automatically ACK when detecting their slave addresses, so there is no option
|
||||||
|
to NACK them. For those reasons, this API does not support NACK in the address
|
||||||
|
phase.
|
||||||
|
|
||||||
|
Currently, there is no slave event to report if the master did ACK or NACK a
|
||||||
|
byte when it reads from us. We could make this an optional event if the need
|
||||||
|
arises. However, cases should be extremely rare because the master is expected
|
||||||
|
to send STOP after that and we have an event for that. Also, keep in mind not
|
||||||
|
all I2C controllers have the possibility to report that event.
|
||||||
|
|
||||||
|
|
||||||
|
About buffers
|
||||||
|
-------------
|
||||||
|
|
||||||
|
During development of this API, the question of using buffers instead of just
|
||||||
|
bytes came up. Such an extension might be possible, usefulness is unclear at
|
||||||
|
this time of writing. Some points to keep in mind when using buffers:
|
||||||
|
|
||||||
|
* Buffers should be opt-in and slave drivers will always have to support
|
||||||
|
byte-based transactions as the ultimate fallback because this is how the
|
||||||
|
majority of HW works.
|
||||||
|
|
||||||
|
* For backends simulating hardware registers, buffers are not helpful because
|
||||||
|
on writes an action should be immediately triggered. For reads, the data in
|
||||||
|
the buffer might get stale.
|
||||||
|
|
||||||
|
* A master can send STOP at any time. For partially transferred buffers, this
|
||||||
|
means additional code to handle this exception. Such code tends to be
|
||||||
|
error-prone.
|
||||||
|
|
|
@ -41,7 +41,3 @@ integrated than Algorithm and Adapter.
|
||||||
|
|
||||||
For a given configuration, you will need a driver for your I2C bus, and
|
For a given configuration, you will need a driver for your I2C bus, and
|
||||||
drivers for your I2C devices (usually one driver for each device).
|
drivers for your I2C devices (usually one driver for each device).
|
||||||
|
|
||||||
At this time, Linux only operates I2C (or SMBus) in master mode; you can't
|
|
||||||
use these APIs to make a Linux system behave as a slave/device, either to
|
|
||||||
speak a custom protocol or to emulate some other device.
|
|
||||||
|
|
|
@ -485,6 +485,15 @@ config I2C_DESIGNWARE_BAYTRAIL
|
||||||
the platform firmware controlling it. You should say Y if running on
|
the platform firmware controlling it. You should say Y if running on
|
||||||
a BayTrail system using the AXP288.
|
a BayTrail system using the AXP288.
|
||||||
|
|
||||||
|
config I2C_DIGICOLOR
|
||||||
|
tristate "Conexant Digicolor I2C driver"
|
||||||
|
depends on ARCH_DIGICOLOR
|
||||||
|
help
|
||||||
|
Support for Conexant Digicolor SoCs (CX92755) I2C controller driver.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called i2c-digicolor.
|
||||||
|
|
||||||
config I2C_EFM32
|
config I2C_EFM32
|
||||||
tristate "EFM32 I2C controller"
|
tristate "EFM32 I2C controller"
|
||||||
depends on ARCH_EFM32 || COMPILE_TEST
|
depends on ARCH_EFM32 || COMPILE_TEST
|
||||||
|
@ -574,6 +583,15 @@ config I2C_IOP3XX
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called i2c-iop3xx.
|
will be called i2c-iop3xx.
|
||||||
|
|
||||||
|
config I2C_JZ4780
|
||||||
|
tristate "JZ4780 I2C controller interface support"
|
||||||
|
depends on MACH_JZ4780 || COMPILE_TEST
|
||||||
|
help
|
||||||
|
If you say yes to this option, support will be included for the
|
||||||
|
Ingenic JZ4780 I2C controller.
|
||||||
|
|
||||||
|
If you don't know what to do here, say N.
|
||||||
|
|
||||||
config I2C_KEMPLD
|
config I2C_KEMPLD
|
||||||
tristate "Kontron COM I2C Controller"
|
tristate "Kontron COM I2C Controller"
|
||||||
depends on MFD_KEMPLD
|
depends on MFD_KEMPLD
|
||||||
|
@ -898,6 +916,16 @@ config I2C_XLR
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called i2c-xlr.
|
will be called i2c-xlr.
|
||||||
|
|
||||||
|
config I2C_XLP9XX
|
||||||
|
tristate "XLP9XX I2C support"
|
||||||
|
depends on CPU_XLP || COMPILE_TEST
|
||||||
|
help
|
||||||
|
This driver enables support for the on-chip I2C interface of
|
||||||
|
the Broadcom XLP9xx/XLP5xx MIPS processors.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module will
|
||||||
|
be called i2c-xlp9xx.
|
||||||
|
|
||||||
config I2C_RCAR
|
config I2C_RCAR
|
||||||
tristate "Renesas R-Car I2C Controller"
|
tristate "Renesas R-Car I2C Controller"
|
||||||
depends on ARCH_SHMOBILE || COMPILE_TEST
|
depends on ARCH_SHMOBILE || COMPILE_TEST
|
||||||
|
|
|
@ -45,6 +45,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o
|
||||||
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
|
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
|
||||||
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
|
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
|
||||||
i2c-designware-pci-objs := i2c-designware-pcidrv.o
|
i2c-designware-pci-objs := i2c-designware-pcidrv.o
|
||||||
|
obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o
|
||||||
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
|
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
|
||||||
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
|
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
|
||||||
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
|
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
|
||||||
|
@ -55,6 +56,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
|
||||||
obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o
|
obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o
|
||||||
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
|
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
|
||||||
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
||||||
|
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
|
||||||
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
|
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
|
||||||
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
|
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
|
||||||
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
||||||
|
@ -87,6 +89,7 @@ obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
|
||||||
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
|
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
|
||||||
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
|
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
|
||||||
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
|
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
|
||||||
|
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
|
||||||
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
|
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
|
||||||
|
|
||||||
# External I2C/SMBus adapter drivers
|
# External I2C/SMBus adapter drivers
|
||||||
|
|
|
@ -381,6 +381,7 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
|
||||||
static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned long time_left;
|
||||||
bool has_unre_flag = dev->pdata->has_unre_flag;
|
bool has_unre_flag = dev->pdata->has_unre_flag;
|
||||||
|
|
||||||
dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
|
dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
|
||||||
|
@ -436,9 +437,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&dev->cmd_complete,
|
time_left = wait_for_completion_timeout(&dev->cmd_complete,
|
||||||
dev->adapter.timeout);
|
dev->adapter.timeout);
|
||||||
if (ret == 0) {
|
if (time_left == 0) {
|
||||||
dev_err(dev->dev, "controller timed out\n");
|
dev_err(dev->dev, "controller timed out\n");
|
||||||
at91_init_twi_bus(dev);
|
at91_init_twi_bus(dev);
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
|
@ -487,30 +488,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
if (num == 2) {
|
||||||
* The hardware can handle at most two messages concatenated by a
|
|
||||||
* repeated start via it's internal address feature.
|
|
||||||
*/
|
|
||||||
if (num > 2) {
|
|
||||||
dev_err(dev->dev,
|
|
||||||
"cannot handle more than two concatenated messages.\n");
|
|
||||||
ret = 0;
|
|
||||||
goto out;
|
|
||||||
} else if (num == 2) {
|
|
||||||
int internal_address = 0;
|
int internal_address = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (msg->flags & I2C_M_RD) {
|
|
||||||
dev_err(dev->dev, "first transfer must be write.\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (msg->len > 3) {
|
|
||||||
dev_err(dev->dev, "first message size must be <= 3.\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 1st msg is put into the internal address, start with 2nd */
|
/* 1st msg is put into the internal address, start with 2nd */
|
||||||
m_start = &msg[1];
|
m_start = &msg[1];
|
||||||
for (i = 0; i < msg->len; ++i) {
|
for (i = 0; i < msg->len; ++i) {
|
||||||
|
@ -540,6 +521,15 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The hardware can handle at most two messages concatenated by a
|
||||||
|
* repeated start via it's internal address feature.
|
||||||
|
*/
|
||||||
|
static struct i2c_adapter_quirks at91_twi_quirks = {
|
||||||
|
.flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
|
||||||
|
.max_comb_1st_msg_len = 3,
|
||||||
|
};
|
||||||
|
|
||||||
static u32 at91_twi_func(struct i2c_adapter *adapter)
|
static u32 at91_twi_func(struct i2c_adapter *adapter)
|
||||||
{
|
{
|
||||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
|
||||||
|
@ -777,6 +767,7 @@ static int at91_twi_probe(struct platform_device *pdev)
|
||||||
dev->adapter.owner = THIS_MODULE;
|
dev->adapter.owner = THIS_MODULE;
|
||||||
dev->adapter.class = I2C_CLASS_DEPRECATED;
|
dev->adapter.class = I2C_CLASS_DEPRECATED;
|
||||||
dev->adapter.algo = &at91_twi_algorithm;
|
dev->adapter.algo = &at91_twi_algorithm;
|
||||||
|
dev->adapter.quirks = &at91_twi_quirks;
|
||||||
dev->adapter.dev.parent = dev->dev;
|
dev->adapter.dev.parent = dev->dev;
|
||||||
dev->adapter.nr = pdev->id;
|
dev->adapter.nr = pdev->id;
|
||||||
dev->adapter.timeout = AT91_I2C_TIMEOUT;
|
dev->adapter.timeout = AT91_I2C_TIMEOUT;
|
||||||
|
|
|
@ -334,12 +334,7 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||||
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
|
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
|
||||||
u32 rx_xfer, tx_xfer;
|
u32 rx_xfer, tx_xfer;
|
||||||
u32 addr_1, addr_2;
|
u32 addr_1, addr_2;
|
||||||
int ret;
|
unsigned long time_left;
|
||||||
|
|
||||||
if (msg->len > 255) {
|
|
||||||
dev_warn(idev->dev, "unsupported length %u\n", msg->len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
idev->msg = msg;
|
idev->msg = msg;
|
||||||
idev->msg_xfrd = 0;
|
idev->msg_xfrd = 0;
|
||||||
|
@ -388,15 +383,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||||
|
|
||||||
i2c_int_enable(idev, int_mask);
|
i2c_int_enable(idev, int_mask);
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&idev->msg_complete,
|
time_left = wait_for_completion_timeout(&idev->msg_complete,
|
||||||
I2C_XFER_TIMEOUT);
|
I2C_XFER_TIMEOUT);
|
||||||
|
|
||||||
i2c_int_disable(idev, int_mask);
|
i2c_int_disable(idev, int_mask);
|
||||||
|
|
||||||
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
|
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
|
||||||
dev_warn(idev->dev, "busy after xfer\n");
|
dev_warn(idev->dev, "busy after xfer\n");
|
||||||
|
|
||||||
if (ret == 0)
|
if (time_left == 0)
|
||||||
idev->msg_err = -ETIMEDOUT;
|
idev->msg_err = -ETIMEDOUT;
|
||||||
|
|
||||||
if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
|
if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
|
||||||
|
@ -408,17 +403,17 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||||
static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
|
static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
|
||||||
{
|
{
|
||||||
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
|
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
|
||||||
int ret;
|
unsigned long time_left;
|
||||||
|
|
||||||
reinit_completion(&idev->msg_complete);
|
reinit_completion(&idev->msg_complete);
|
||||||
|
|
||||||
/* Issue stop */
|
/* Issue stop */
|
||||||
writel(0xb, idev->base + MST_COMMAND);
|
writel(0xb, idev->base + MST_COMMAND);
|
||||||
i2c_int_enable(idev, int_mask);
|
i2c_int_enable(idev, int_mask);
|
||||||
ret = wait_for_completion_timeout(&idev->msg_complete,
|
time_left = wait_for_completion_timeout(&idev->msg_complete,
|
||||||
I2C_STOP_TIMEOUT);
|
I2C_STOP_TIMEOUT);
|
||||||
i2c_int_disable(idev, int_mask);
|
i2c_int_disable(idev, int_mask);
|
||||||
if (ret == 0)
|
if (time_left == 0)
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
|
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
|
||||||
|
@ -454,6 +449,11 @@ static const struct i2c_algorithm axxia_i2c_algo = {
|
||||||
.functionality = axxia_i2c_func,
|
.functionality = axxia_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct i2c_adapter_quirks axxia_i2c_quirks = {
|
||||||
|
.max_read_len = 255,
|
||||||
|
.max_write_len = 255,
|
||||||
|
};
|
||||||
|
|
||||||
static int axxia_i2c_probe(struct platform_device *pdev)
|
static int axxia_i2c_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
@ -511,6 +511,7 @@ static int axxia_i2c_probe(struct platform_device *pdev)
|
||||||
strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
|
strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
|
||||||
idev->adapter.owner = THIS_MODULE;
|
idev->adapter.owner = THIS_MODULE;
|
||||||
idev->adapter.algo = &axxia_i2c_algo;
|
idev->adapter.algo = &axxia_i2c_algo;
|
||||||
|
idev->adapter.quirks = &axxia_i2c_quirks;
|
||||||
idev->adapter.dev.parent = &pdev->dev;
|
idev->adapter.dev.parent = &pdev->dev;
|
||||||
idev->adapter.dev.of_node = pdev->dev.of_node;
|
idev->adapter.dev.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
|
|
|
@ -160,14 +160,6 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||||
u32 val;
|
u32 val;
|
||||||
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
|
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
|
||||||
|
|
||||||
/* need to reserve one byte in the FIFO for the slave address */
|
|
||||||
if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
|
|
||||||
dev_err(iproc_i2c->device,
|
|
||||||
"only support data length up to %u bytes\n",
|
|
||||||
M_TX_RX_FIFO_SIZE - 1);
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if bus is busy */
|
/* check if bus is busy */
|
||||||
if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
|
if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
|
||||||
BIT(M_CMD_START_BUSY_SHIFT))) {
|
BIT(M_CMD_START_BUSY_SHIFT))) {
|
||||||
|
@ -287,6 +279,12 @@ static const struct i2c_algorithm bcm_iproc_algo = {
|
||||||
.functionality = bcm_iproc_i2c_functionality,
|
.functionality = bcm_iproc_i2c_functionality,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
|
||||||
|
/* need to reserve one byte in the FIFO for the slave address */
|
||||||
|
.max_read_len = M_TX_RX_FIFO_SIZE - 1,
|
||||||
|
.max_write_len = M_TX_RX_FIFO_SIZE - 1,
|
||||||
|
};
|
||||||
|
|
||||||
static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
|
static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
|
||||||
{
|
{
|
||||||
unsigned int bus_speed;
|
unsigned int bus_speed;
|
||||||
|
@ -413,6 +411,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
|
||||||
i2c_set_adapdata(adap, iproc_i2c);
|
i2c_set_adapdata(adap, iproc_i2c);
|
||||||
strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
|
strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
|
||||||
adap->algo = &bcm_iproc_algo;
|
adap->algo = &bcm_iproc_algo;
|
||||||
|
adap->quirks = &bcm_iproc_i2c_quirks;
|
||||||
adap->dev.parent = &pdev->dev;
|
adap->dev.parent = &pdev->dev;
|
||||||
adap->dev.of_node = pdev->dev.of_node;
|
adap->dev.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
|
||||||
struct i2c_msg *msg)
|
struct i2c_msg *msg)
|
||||||
{
|
{
|
||||||
u32 c;
|
u32 c;
|
||||||
int time_left;
|
unsigned long time_left;
|
||||||
|
|
||||||
i2c_dev->msg_buf = msg->buf;
|
i2c_dev->msg_buf = msg->buf;
|
||||||
i2c_dev->msg_buf_remaining = msg->len;
|
i2c_dev->msg_buf_remaining = msg->len;
|
||||||
|
|
|
@ -475,7 +475,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap)
|
||||||
static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
|
static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
|
||||||
struct i2c_adapter *adap)
|
struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
int ret;
|
unsigned long time_left;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
id->p_msg = msg;
|
id->p_msg = msg;
|
||||||
|
@ -501,8 +501,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
|
||||||
cdns_i2c_msend(id);
|
cdns_i2c_msend(id);
|
||||||
|
|
||||||
/* Wait for the signal of completion */
|
/* Wait for the signal of completion */
|
||||||
ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
|
time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
|
||||||
if (!ret) {
|
if (time_left == 0) {
|
||||||
cdns_i2c_master_reset(adap);
|
cdns_i2c_master_reset(adap);
|
||||||
dev_err(id->adap.dev.parent,
|
dev_err(id->adap.dev.parent,
|
||||||
"timeout waiting on completion\n");
|
"timeout waiting on completion\n");
|
||||||
|
|
|
@ -308,22 +308,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||||
struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
|
struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
|
||||||
struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
|
struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
|
||||||
struct i2c_msg *pmsg;
|
struct i2c_msg *pmsg;
|
||||||
int ret, i;
|
int ret;
|
||||||
int tptr;
|
int tptr;
|
||||||
int rptr;
|
int rptr;
|
||||||
cbd_t __iomem *tbdf;
|
cbd_t __iomem *tbdf;
|
||||||
cbd_t __iomem *rbdf;
|
cbd_t __iomem *rbdf;
|
||||||
|
|
||||||
if (num > CPM_MAXBD)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Check if we have any oversized READ requests */
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
pmsg = &msgs[i];
|
|
||||||
if (pmsg->len >= CPM_MAX_READ)
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset to use first buffer */
|
/* Reset to use first buffer */
|
||||||
out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
|
out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
|
||||||
out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
|
out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
|
||||||
|
@ -424,10 +414,18 @@ static const struct i2c_algorithm cpm_i2c_algo = {
|
||||||
.functionality = cpm_i2c_func,
|
.functionality = cpm_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* CPM_MAX_READ is also limiting writes according to the code! */
|
||||||
|
static struct i2c_adapter_quirks cpm_i2c_quirks = {
|
||||||
|
.max_num_msgs = CPM_MAXBD,
|
||||||
|
.max_read_len = CPM_MAX_READ,
|
||||||
|
.max_write_len = CPM_MAX_READ,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct i2c_adapter cpm_ops = {
|
static const struct i2c_adapter cpm_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "i2c-cpm",
|
.name = "i2c-cpm",
|
||||||
.algo = &cpm_i2c_algo,
|
.algo = &cpm_i2c_algo,
|
||||||
|
.quirks = &cpm_i2c_quirks,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cpm_i2c_setup(struct cpm_i2c *cpm)
|
static int cpm_i2c_setup(struct cpm_i2c *cpm)
|
||||||
|
|
|
@ -60,6 +60,12 @@
|
||||||
#define DAVINCI_I2C_IVR_REG 0x28
|
#define DAVINCI_I2C_IVR_REG 0x28
|
||||||
#define DAVINCI_I2C_EMDR_REG 0x2c
|
#define DAVINCI_I2C_EMDR_REG 0x2c
|
||||||
#define DAVINCI_I2C_PSC_REG 0x30
|
#define DAVINCI_I2C_PSC_REG 0x30
|
||||||
|
#define DAVINCI_I2C_FUNC_REG 0x48
|
||||||
|
#define DAVINCI_I2C_DIR_REG 0x4c
|
||||||
|
#define DAVINCI_I2C_DIN_REG 0x50
|
||||||
|
#define DAVINCI_I2C_DOUT_REG 0x54
|
||||||
|
#define DAVINCI_I2C_DSET_REG 0x58
|
||||||
|
#define DAVINCI_I2C_DCLR_REG 0x5c
|
||||||
|
|
||||||
#define DAVINCI_I2C_IVR_AAS 0x07
|
#define DAVINCI_I2C_IVR_AAS 0x07
|
||||||
#define DAVINCI_I2C_IVR_SCD 0x06
|
#define DAVINCI_I2C_IVR_SCD 0x06
|
||||||
|
@ -93,6 +99,29 @@
|
||||||
#define DAVINCI_I2C_IMR_NACK BIT(1)
|
#define DAVINCI_I2C_IMR_NACK BIT(1)
|
||||||
#define DAVINCI_I2C_IMR_AL BIT(0)
|
#define DAVINCI_I2C_IMR_AL BIT(0)
|
||||||
|
|
||||||
|
/* set SDA and SCL as GPIO */
|
||||||
|
#define DAVINCI_I2C_FUNC_PFUNC0 BIT(0)
|
||||||
|
|
||||||
|
/* set SCL as output when used as GPIO*/
|
||||||
|
#define DAVINCI_I2C_DIR_PDIR0 BIT(0)
|
||||||
|
/* set SDA as output when used as GPIO*/
|
||||||
|
#define DAVINCI_I2C_DIR_PDIR1 BIT(1)
|
||||||
|
|
||||||
|
/* read SCL GPIO level */
|
||||||
|
#define DAVINCI_I2C_DIN_PDIN0 BIT(0)
|
||||||
|
/* read SDA GPIO level */
|
||||||
|
#define DAVINCI_I2C_DIN_PDIN1 BIT(1)
|
||||||
|
|
||||||
|
/*set the SCL GPIO high */
|
||||||
|
#define DAVINCI_I2C_DSET_PDSET0 BIT(0)
|
||||||
|
/*set the SDA GPIO high */
|
||||||
|
#define DAVINCI_I2C_DSET_PDSET1 BIT(1)
|
||||||
|
|
||||||
|
/* set the SCL GPIO low */
|
||||||
|
#define DAVINCI_I2C_DCLR_PDCLR0 BIT(0)
|
||||||
|
/* set the SDA GPIO low */
|
||||||
|
#define DAVINCI_I2C_DCLR_PDCLR1 BIT(1)
|
||||||
|
|
||||||
struct davinci_i2c_dev {
|
struct davinci_i2c_dev {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
@ -129,43 +158,6 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
|
||||||
return readw_relaxed(i2c_dev->base + reg);
|
return readw_relaxed(i2c_dev->base + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate a pulse on the i2c clock pin. */
|
|
||||||
static void davinci_i2c_clock_pulse(unsigned int scl_pin)
|
|
||||||
{
|
|
||||||
u16 i;
|
|
||||||
|
|
||||||
if (scl_pin) {
|
|
||||||
/* Send high and low on the SCL line */
|
|
||||||
for (i = 0; i < 9; i++) {
|
|
||||||
gpio_set_value(scl_pin, 0);
|
|
||||||
udelay(20);
|
|
||||||
gpio_set_value(scl_pin, 1);
|
|
||||||
udelay(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This routine does i2c bus recovery as specified in the
|
|
||||||
* i2c protocol Rev. 03 section 3.16 titled "Bus clear"
|
|
||||||
*/
|
|
||||||
static void davinci_i2c_recover_bus(struct davinci_i2c_dev *dev)
|
|
||||||
{
|
|
||||||
u32 flag = 0;
|
|
||||||
struct davinci_i2c_platform_data *pdata = dev->pdata;
|
|
||||||
|
|
||||||
dev_err(dev->dev, "initiating i2c bus recovery\n");
|
|
||||||
/* Send NACK to the slave */
|
|
||||||
flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
|
|
||||||
flag |= DAVINCI_I2C_MDR_NACK;
|
|
||||||
/* write the data into mode register */
|
|
||||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
|
|
||||||
davinci_i2c_clock_pulse(pdata->scl_pin);
|
|
||||||
/* Send STOP */
|
|
||||||
flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
|
|
||||||
flag |= DAVINCI_I2C_MDR_STP;
|
|
||||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
|
static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
|
||||||
int val)
|
int val)
|
||||||
{
|
{
|
||||||
|
@ -262,6 +254,99 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine does i2c bus recovery by using i2c_generic_gpio_recovery
|
||||||
|
* which is provided by I2C Bus recovery infrastructure.
|
||||||
|
*/
|
||||||
|
static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
|
/* Disable interrupts */
|
||||||
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, 0);
|
||||||
|
|
||||||
|
/* put I2C into reset */
|
||||||
|
davinci_i2c_reset_ctrl(dev, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
|
i2c_davinci_init(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = {
|
||||||
|
.recover_bus = i2c_generic_gpio_recovery,
|
||||||
|
.prepare_recovery = davinci_i2c_prepare_recovery,
|
||||||
|
.unprepare_recovery = davinci_i2c_unprepare_recovery,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val)
|
||||||
|
{
|
||||||
|
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_DSET_REG,
|
||||||
|
DAVINCI_I2C_DSET_PDSET0);
|
||||||
|
else
|
||||||
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_DCLR_REG,
|
||||||
|
DAVINCI_I2C_DCLR_PDCLR0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int davinci_i2c_get_scl(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
int val;
|
||||||
|
|
||||||
|
/* read the state of SCL */
|
||||||
|
val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
|
||||||
|
return val & DAVINCI_I2C_DIN_PDIN0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int davinci_i2c_get_sda(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
int val;
|
||||||
|
|
||||||
|
/* read the state of SDA */
|
||||||
|
val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
|
||||||
|
return val & DAVINCI_I2C_DIN_PDIN1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void davinci_i2c_scl_prepare_recovery(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
|
davinci_i2c_prepare_recovery(adap);
|
||||||
|
|
||||||
|
/* SCL output, SDA input */
|
||||||
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_DIR_REG, DAVINCI_I2C_DIR_PDIR0);
|
||||||
|
|
||||||
|
/* change to GPIO mode */
|
||||||
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG,
|
||||||
|
DAVINCI_I2C_FUNC_PFUNC0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void davinci_i2c_scl_unprepare_recovery(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
|
/* change back to I2C mode */
|
||||||
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, 0);
|
||||||
|
|
||||||
|
davinci_i2c_unprepare_recovery(adap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = {
|
||||||
|
.recover_bus = i2c_generic_scl_recovery,
|
||||||
|
.set_scl = davinci_i2c_set_scl,
|
||||||
|
.get_scl = davinci_i2c_get_scl,
|
||||||
|
.get_sda = davinci_i2c_get_sda,
|
||||||
|
.prepare_recovery = davinci_i2c_scl_prepare_recovery,
|
||||||
|
.unprepare_recovery = davinci_i2c_scl_unprepare_recovery,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Waiting for bus not busy
|
* Waiting for bus not busy
|
||||||
*/
|
*/
|
||||||
|
@ -282,8 +367,7 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
} else {
|
} else {
|
||||||
to_cnt = 0;
|
to_cnt = 0;
|
||||||
davinci_i2c_recover_bus(dev);
|
i2c_recover_bus(&dev->adapter);
|
||||||
i2c_davinci_init(dev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allow_sleep)
|
if (allow_sleep)
|
||||||
|
@ -304,7 +388,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
||||||
struct davinci_i2c_platform_data *pdata = dev->pdata;
|
struct davinci_i2c_platform_data *pdata = dev->pdata;
|
||||||
u32 flag;
|
u32 flag;
|
||||||
u16 w;
|
u16 w;
|
||||||
int r;
|
unsigned long time_left;
|
||||||
|
|
||||||
/* Introduce a delay, required for some boards (e.g Davinci EVM) */
|
/* Introduce a delay, required for some boards (e.g Davinci EVM) */
|
||||||
if (pdata->bus_delay)
|
if (pdata->bus_delay)
|
||||||
|
@ -368,11 +452,11 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
||||||
flag |= DAVINCI_I2C_MDR_STP;
|
flag |= DAVINCI_I2C_MDR_STP;
|
||||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
|
||||||
|
|
||||||
r = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout);
|
time_left = wait_for_completion_timeout(&dev->cmd_complete,
|
||||||
if (r == 0) {
|
dev->adapter.timeout);
|
||||||
|
if (!time_left) {
|
||||||
dev_err(dev->dev, "controller timed out\n");
|
dev_err(dev->dev, "controller timed out\n");
|
||||||
davinci_i2c_recover_bus(dev);
|
i2c_recover_bus(adap);
|
||||||
i2c_davinci_init(dev);
|
|
||||||
dev->buf_len = 0;
|
dev->buf_len = 0;
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
@ -380,17 +464,13 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
|
||||||
/* This should be 0 if all bytes were transferred
|
/* This should be 0 if all bytes were transferred
|
||||||
* or dev->cmd_err denotes an error.
|
* or dev->cmd_err denotes an error.
|
||||||
*/
|
*/
|
||||||
if (r >= 0) {
|
dev_err(dev->dev, "abnormal termination buf_len=%i\n",
|
||||||
dev_err(dev->dev, "abnormal termination buf_len=%i\n",
|
dev->buf_len);
|
||||||
dev->buf_len);
|
|
||||||
r = -EREMOTEIO;
|
|
||||||
}
|
|
||||||
dev->terminate = 1;
|
dev->terminate = 1;
|
||||||
wmb();
|
wmb();
|
||||||
dev->buf_len = 0;
|
dev->buf_len = 0;
|
||||||
|
return -EREMOTEIO;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* no error */
|
/* no error */
|
||||||
if (likely(!dev->cmd_err))
|
if (likely(!dev->cmd_err))
|
||||||
|
@ -674,6 +754,10 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
||||||
if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||||
&prop))
|
&prop))
|
||||||
dev->pdata->bus_freq = prop / 1000;
|
dev->pdata->bus_freq = prop / 1000;
|
||||||
|
|
||||||
|
dev->pdata->has_pfunc =
|
||||||
|
of_property_read_bool(pdev->dev.of_node,
|
||||||
|
"ti,has-pfunc");
|
||||||
} else if (!dev->pdata) {
|
} else if (!dev->pdata) {
|
||||||
dev->pdata = &davinci_i2c_platform_data_default;
|
dev->pdata = &davinci_i2c_platform_data_default;
|
||||||
}
|
}
|
||||||
|
@ -715,6 +799,14 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
||||||
adap->timeout = DAVINCI_I2C_TIMEOUT;
|
adap->timeout = DAVINCI_I2C_TIMEOUT;
|
||||||
adap->dev.of_node = pdev->dev.of_node;
|
adap->dev.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
adap->nr = pdev->id;
|
adap->nr = pdev->id;
|
||||||
r = i2c_add_numbered_adapter(adap);
|
r = i2c_add_numbered_adapter(adap);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
|
|
@ -656,8 +656,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||||
i2c_dw_xfer_init(dev);
|
i2c_dw_xfer_init(dev);
|
||||||
|
|
||||||
/* wait for tx to complete */
|
/* wait for tx to complete */
|
||||||
ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
|
if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
|
||||||
if (ret == 0) {
|
|
||||||
dev_err(dev->dev, "controller timed out\n");
|
dev_err(dev->dev, "controller timed out\n");
|
||||||
/* i2c_dw_init implicitly disables the adapter */
|
/* i2c_dw_init implicitly disables the adapter */
|
||||||
i2c_dw_init(dev);
|
i2c_dw_init(dev);
|
||||||
|
|
|
@ -143,10 +143,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
|
||||||
u32 clk_freq, ht = 0;
|
u32 clk_freq, ht = 0;
|
||||||
|
|
||||||
irq = platform_get_irq(pdev, 0);
|
irq = platform_get_irq(pdev, 0);
|
||||||
if (irq < 0) {
|
if (irq < 0)
|
||||||
dev_err(&pdev->dev, "no irq resource?\n");
|
return irq;
|
||||||
return irq; /* -ENXIO */
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
|
dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
|
|
|
@ -0,0 +1,385 @@
|
||||||
|
/*
|
||||||
|
* I2C bus driver for Conexant Digicolor SoCs
|
||||||
|
*
|
||||||
|
* Author: Baruch Siach <baruch@tkos.co.il>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Paradox Innovation Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#define DEFAULT_FREQ 100000
|
||||||
|
#define TIMEOUT_MS 100
|
||||||
|
|
||||||
|
#define II_CONTROL 0x0
|
||||||
|
#define II_CONTROL_LOCAL_RESET BIT(0)
|
||||||
|
|
||||||
|
#define II_CLOCKTIME 0x1
|
||||||
|
|
||||||
|
#define II_COMMAND 0x2
|
||||||
|
#define II_CMD_START 1
|
||||||
|
#define II_CMD_RESTART 2
|
||||||
|
#define II_CMD_SEND_ACK 3
|
||||||
|
#define II_CMD_GET_ACK 6
|
||||||
|
#define II_CMD_GET_NOACK 7
|
||||||
|
#define II_CMD_STOP 10
|
||||||
|
#define II_COMMAND_GO BIT(7)
|
||||||
|
#define II_COMMAND_COMPLETION_STATUS(r) (((r) >> 5) & 3)
|
||||||
|
#define II_CMD_STATUS_NORMAL 0
|
||||||
|
#define II_CMD_STATUS_ACK_GOOD 1
|
||||||
|
#define II_CMD_STATUS_ACK_BAD 2
|
||||||
|
#define II_CMD_STATUS_ABORT 3
|
||||||
|
|
||||||
|
#define II_DATA 0x3
|
||||||
|
#define II_INTFLAG_CLEAR 0x8
|
||||||
|
#define II_INTENABLE 0xa
|
||||||
|
|
||||||
|
struct dc_i2c {
|
||||||
|
struct i2c_adapter adap;
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *regs;
|
||||||
|
struct clk *clk;
|
||||||
|
unsigned int frequency;
|
||||||
|
|
||||||
|
struct i2c_msg *msg;
|
||||||
|
unsigned int msgbuf_ptr;
|
||||||
|
int last;
|
||||||
|
spinlock_t lock;
|
||||||
|
struct completion done;
|
||||||
|
int state;
|
||||||
|
int error;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STATE_IDLE,
|
||||||
|
STATE_START,
|
||||||
|
STATE_ADDR,
|
||||||
|
STATE_WRITE,
|
||||||
|
STATE_READ,
|
||||||
|
STATE_STOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd)
|
||||||
|
{
|
||||||
|
writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 dc_i2c_addr_cmd(struct i2c_msg *msg)
|
||||||
|
{
|
||||||
|
u8 addr = (msg->addr & 0x7f) << 1;
|
||||||
|
|
||||||
|
if (msg->flags & I2C_M_RD)
|
||||||
|
addr |= 1;
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_data(struct dc_i2c *i2c, u8 data)
|
||||||
|
{
|
||||||
|
writeb_relaxed(data, i2c->regs + II_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte)
|
||||||
|
{
|
||||||
|
dc_i2c_data(i2c, byte);
|
||||||
|
dc_i2c_cmd(i2c, II_CMD_SEND_ACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_write_buf(struct dc_i2c *i2c)
|
||||||
|
{
|
||||||
|
dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_next_read(struct dc_i2c *i2c)
|
||||||
|
{
|
||||||
|
bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len);
|
||||||
|
|
||||||
|
dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_stop(struct dc_i2c *i2c)
|
||||||
|
{
|
||||||
|
i2c->state = STATE_STOP;
|
||||||
|
if (i2c->last)
|
||||||
|
dc_i2c_cmd(i2c, II_CMD_STOP);
|
||||||
|
else
|
||||||
|
complete(&i2c->done);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 dc_i2c_read_byte(struct dc_i2c *i2c)
|
||||||
|
{
|
||||||
|
return readb_relaxed(i2c->regs + II_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_read_buf(struct dc_i2c *i2c)
|
||||||
|
{
|
||||||
|
i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c);
|
||||||
|
dc_i2c_next_read(i2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
|
||||||
|
writeb_relaxed(!!enable, i2c->regs + II_INTENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dc_i2c_cmd_status(struct dc_i2c *i2c)
|
||||||
|
{
|
||||||
|
u8 cmd = readb_relaxed(i2c->regs + II_COMMAND);
|
||||||
|
|
||||||
|
return II_COMMAND_COMPLETION_STATUS(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dc_i2c_start_msg(struct dc_i2c *i2c, int first)
|
||||||
|
{
|
||||||
|
struct i2c_msg *msg = i2c->msg;
|
||||||
|
|
||||||
|
if (!(msg->flags & I2C_M_NOSTART)) {
|
||||||
|
i2c->state = STATE_START;
|
||||||
|
dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART);
|
||||||
|
} else if (msg->flags & I2C_M_RD) {
|
||||||
|
i2c->state = STATE_READ;
|
||||||
|
dc_i2c_next_read(i2c);
|
||||||
|
} else {
|
||||||
|
i2c->state = STATE_WRITE;
|
||||||
|
dc_i2c_write_buf(i2c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct dc_i2c *i2c = dev_id;
|
||||||
|
int cmd_status = dc_i2c_cmd_status(i2c);
|
||||||
|
unsigned long flags;
|
||||||
|
u8 addr_cmd;
|
||||||
|
|
||||||
|
writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
|
||||||
|
if (cmd_status == II_CMD_STATUS_ACK_BAD
|
||||||
|
|| cmd_status == II_CMD_STATUS_ABORT) {
|
||||||
|
i2c->error = -EIO;
|
||||||
|
complete(&i2c->done);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (i2c->state) {
|
||||||
|
case STATE_START:
|
||||||
|
addr_cmd = dc_i2c_addr_cmd(i2c->msg);
|
||||||
|
dc_i2c_write_byte(i2c, addr_cmd);
|
||||||
|
i2c->state = STATE_ADDR;
|
||||||
|
break;
|
||||||
|
case STATE_ADDR:
|
||||||
|
if (i2c->msg->flags & I2C_M_RD) {
|
||||||
|
dc_i2c_next_read(i2c);
|
||||||
|
i2c->state = STATE_READ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i2c->state = STATE_WRITE;
|
||||||
|
/* fall through */
|
||||||
|
case STATE_WRITE:
|
||||||
|
if (i2c->msgbuf_ptr < i2c->msg->len)
|
||||||
|
dc_i2c_write_buf(i2c);
|
||||||
|
else
|
||||||
|
dc_i2c_stop(i2c);
|
||||||
|
break;
|
||||||
|
case STATE_READ:
|
||||||
|
if (i2c->msgbuf_ptr < i2c->msg->len)
|
||||||
|
dc_i2c_read_buf(i2c);
|
||||||
|
else
|
||||||
|
dc_i2c_stop(i2c);
|
||||||
|
break;
|
||||||
|
case STATE_STOP:
|
||||||
|
i2c->state = STATE_IDLE;
|
||||||
|
complete(&i2c->done);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,
|
||||||
|
int last)
|
||||||
|
{
|
||||||
|
unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
i2c->msg = msg;
|
||||||
|
i2c->msgbuf_ptr = 0;
|
||||||
|
i2c->last = last;
|
||||||
|
i2c->error = 0;
|
||||||
|
|
||||||
|
reinit_completion(&i2c->done);
|
||||||
|
dc_i2c_set_irq(i2c, 1);
|
||||||
|
dc_i2c_start_msg(i2c, first);
|
||||||
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
|
||||||
|
timeout = wait_for_completion_timeout(&i2c->done, timeout);
|
||||||
|
dc_i2c_set_irq(i2c, 0);
|
||||||
|
if (timeout == 0) {
|
||||||
|
i2c->state = STATE_IDLE;
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2c->error)
|
||||||
|
return i2c->error;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||||
|
{
|
||||||
|
struct dc_i2c *i2c = adap->algo_data;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dc_i2c_init_hw(struct dc_i2c *i2c)
|
||||||
|
{
|
||||||
|
unsigned long clk_rate = clk_get_rate(i2c->clk);
|
||||||
|
unsigned int clocktime;
|
||||||
|
|
||||||
|
writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL);
|
||||||
|
udelay(100);
|
||||||
|
writeb_relaxed(0, i2c->regs + II_CONTROL);
|
||||||
|
udelay(100);
|
||||||
|
|
||||||
|
clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency);
|
||||||
|
if (clocktime < 1 || clocktime > 0xff) {
|
||||||
|
dev_err(i2c->dev, "can't set bus speed of %u Hz\n",
|
||||||
|
i2c->frequency);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 dc_i2c_func(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_algorithm dc_i2c_algorithm = {
|
||||||
|
.master_xfer = dc_i2c_xfer,
|
||||||
|
.functionality = dc_i2c_func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dc_i2c_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
struct dc_i2c *i2c;
|
||||||
|
struct resource *r;
|
||||||
|
int ret = 0, irq;
|
||||||
|
|
||||||
|
i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL);
|
||||||
|
if (!i2c)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||||
|
&i2c->frequency))
|
||||||
|
i2c->frequency = DEFAULT_FREQ;
|
||||||
|
|
||||||
|
i2c->dev = &pdev->dev;
|
||||||
|
platform_set_drvdata(pdev, i2c);
|
||||||
|
|
||||||
|
spin_lock_init(&i2c->lock);
|
||||||
|
init_completion(&i2c->done);
|
||||||
|
|
||||||
|
i2c->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(i2c->clk))
|
||||||
|
return PTR_ERR(i2c->clk);
|
||||||
|
|
||||||
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
i2c->regs = devm_ioremap_resource(&pdev->dev, r);
|
||||||
|
if (IS_ERR(i2c->regs))
|
||||||
|
return PTR_ERR(i2c->regs);
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0)
|
||||||
|
return irq;
|
||||||
|
|
||||||
|
ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0,
|
||||||
|
dev_name(&pdev->dev), i2c);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter",
|
||||||
|
sizeof(i2c->adap.name));
|
||||||
|
i2c->adap.owner = THIS_MODULE;
|
||||||
|
i2c->adap.algo = &dc_i2c_algorithm;
|
||||||
|
i2c->adap.dev.parent = &pdev->dev;
|
||||||
|
i2c->adap.dev.of_node = np;
|
||||||
|
i2c->adap.algo_data = i2c;
|
||||||
|
|
||||||
|
ret = dc_i2c_init_hw(i2c);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(i2c->clk);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = i2c_add_adapter(&i2c->adap);
|
||||||
|
if (ret < 0) {
|
||||||
|
clk_unprepare(i2c->clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dc_i2c_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct dc_i2c *i2c = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
i2c_del_adapter(&i2c->adap);
|
||||||
|
clk_disable_unprepare(i2c->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id dc_i2c_match[] = {
|
||||||
|
{ .compatible = "cnxt,cx92755-i2c" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver dc_i2c_driver = {
|
||||||
|
.probe = dc_i2c_probe,
|
||||||
|
.remove = dc_i2c_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "digicolor-i2c",
|
||||||
|
.of_match_table = dc_i2c_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(dc_i2c_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
|
||||||
|
MODULE_DESCRIPTION("Conexant Digicolor I2C master driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -144,7 +144,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
|
||||||
{
|
{
|
||||||
struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
|
struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
|
||||||
struct i2c_msg *pmsg;
|
struct i2c_msg *pmsg;
|
||||||
struct device *dev = &dln2->adapter.dev;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
|
@ -152,11 +151,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
|
||||||
|
|
||||||
pmsg = &msgs[i];
|
pmsg = &msgs[i];
|
||||||
|
|
||||||
if (pmsg->len > DLN2_I2C_MAX_XFER_SIZE) {
|
|
||||||
dev_warn(dev, "maximum transfer size exceeded\n");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pmsg->flags & I2C_M_RD) {
|
if (pmsg->flags & I2C_M_RD) {
|
||||||
ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
|
ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
|
||||||
pmsg->len);
|
pmsg->len);
|
||||||
|
@ -187,6 +181,11 @@ static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
|
||||||
.functionality = dln2_i2c_func,
|
.functionality = dln2_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct i2c_adapter_quirks dln2_i2c_quirks = {
|
||||||
|
.max_read_len = DLN2_I2C_MAX_XFER_SIZE,
|
||||||
|
.max_write_len = DLN2_I2C_MAX_XFER_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
static int dln2_i2c_probe(struct platform_device *pdev)
|
static int dln2_i2c_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -209,7 +208,9 @@ static int dln2_i2c_probe(struct platform_device *pdev)
|
||||||
dln2->adapter.owner = THIS_MODULE;
|
dln2->adapter.owner = THIS_MODULE;
|
||||||
dln2->adapter.class = I2C_CLASS_HWMON;
|
dln2->adapter.class = I2C_CLASS_HWMON;
|
||||||
dln2->adapter.algo = &dln2_i2c_usb_algorithm;
|
dln2->adapter.algo = &dln2_i2c_usb_algorithm;
|
||||||
|
dln2->adapter.quirks = &dln2_i2c_quirks;
|
||||||
dln2->adapter.dev.parent = dev;
|
dln2->adapter.dev.parent = dev;
|
||||||
|
dln2->adapter.dev.of_node = dev->of_node;
|
||||||
i2c_set_adapdata(&dln2->adapter, dln2);
|
i2c_set_adapdata(&dln2->adapter, dln2);
|
||||||
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
|
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
|
||||||
"dln2-i2c", dev_name(pdev->dev.parent), dln2->port);
|
"dln2-i2c", dev_name(pdev->dev.parent), dln2->port);
|
||||||
|
|
|
@ -223,8 +223,6 @@ struct i801_priv {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pci_driver i801_driver;
|
|
||||||
|
|
||||||
#define FEATURE_SMBUS_PEC (1 << 0)
|
#define FEATURE_SMBUS_PEC (1 << 0)
|
||||||
#define FEATURE_BLOCK_BUFFER (1 << 1)
|
#define FEATURE_BLOCK_BUFFER (1 << 1)
|
||||||
#define FEATURE_BLOCK_PROC (1 << 2)
|
#define FEATURE_BLOCK_PROC (1 << 2)
|
||||||
|
@ -1140,7 +1138,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
int err, i;
|
int err, i;
|
||||||
struct i801_priv *priv;
|
struct i801_priv *priv;
|
||||||
|
|
||||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -1182,34 +1180,35 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
}
|
}
|
||||||
priv->features &= ~disable_features;
|
priv->features &= ~disable_features;
|
||||||
|
|
||||||
err = pci_enable_device(dev);
|
err = pcim_enable_device(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
|
dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
|
||||||
err);
|
err);
|
||||||
goto exit;
|
return err;
|
||||||
}
|
}
|
||||||
|
pcim_pin_device(dev);
|
||||||
|
|
||||||
/* Determine the address of the SMBus area */
|
/* Determine the address of the SMBus area */
|
||||||
priv->smba = pci_resource_start(dev, SMBBAR);
|
priv->smba = pci_resource_start(dev, SMBBAR);
|
||||||
if (!priv->smba) {
|
if (!priv->smba) {
|
||||||
dev_err(&dev->dev, "SMBus base address uninitialized, "
|
dev_err(&dev->dev,
|
||||||
"upgrade BIOS\n");
|
"SMBus base address uninitialized, upgrade BIOS\n");
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
|
err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pci_request_region(dev, SMBBAR, i801_driver.name);
|
err = pcim_iomap_regions(dev, 1 << SMBBAR,
|
||||||
|
dev_driver_string(&dev->dev));
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&dev->dev, "Failed to request SMBus region "
|
dev_err(&dev->dev,
|
||||||
"0x%lx-0x%Lx\n", priv->smba,
|
"Failed to request SMBus region 0x%lx-0x%Lx\n",
|
||||||
|
priv->smba,
|
||||||
(unsigned long long)pci_resource_end(dev, SMBBAR));
|
(unsigned long long)pci_resource_end(dev, SMBBAR));
|
||||||
goto exit;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
|
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
|
||||||
|
@ -1254,8 +1253,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
if (priv->features & FEATURE_IRQ) {
|
if (priv->features & FEATURE_IRQ) {
|
||||||
init_waitqueue_head(&priv->waitq);
|
init_waitqueue_head(&priv->waitq);
|
||||||
|
|
||||||
err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
|
err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
|
||||||
i801_driver.name, priv);
|
IRQF_SHARED,
|
||||||
|
dev_driver_string(&dev->dev), priv);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
|
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
|
||||||
dev->irq, err);
|
dev->irq, err);
|
||||||
|
@ -1276,7 +1276,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
err = i2c_add_adapter(&priv->adapter);
|
err = i2c_add_adapter(&priv->adapter);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
|
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
|
||||||
goto exit_free_irq;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
i801_probe_optional_slaves(priv);
|
i801_probe_optional_slaves(priv);
|
||||||
|
@ -1286,14 +1286,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
pci_set_drvdata(dev, priv);
|
pci_set_drvdata(dev, priv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_free_irq:
|
|
||||||
if (priv->features & FEATURE_IRQ)
|
|
||||||
free_irq(dev->irq, priv);
|
|
||||||
pci_release_region(dev, SMBBAR);
|
|
||||||
exit:
|
|
||||||
kfree(priv);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void i801_remove(struct pci_dev *dev)
|
static void i801_remove(struct pci_dev *dev)
|
||||||
|
@ -1304,11 +1296,6 @@ static void i801_remove(struct pci_dev *dev)
|
||||||
i2c_del_adapter(&priv->adapter);
|
i2c_del_adapter(&priv->adapter);
|
||||||
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
||||||
|
|
||||||
if (priv->features & FEATURE_IRQ)
|
|
||||||
free_irq(dev->irq, priv);
|
|
||||||
pci_release_region(dev, SMBBAR);
|
|
||||||
|
|
||||||
kfree(priv);
|
|
||||||
/*
|
/*
|
||||||
* do not call pci_disable_device(dev) since it can cause hard hangs on
|
* do not call pci_disable_device(dev) since it can cause hard hangs on
|
||||||
* some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
|
* some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
|
||||||
|
@ -1330,7 +1317,7 @@ static int i801_resume(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
pci_set_power_state(dev, PCI_D0);
|
pci_set_power_state(dev, PCI_D0);
|
||||||
pci_restore_state(dev);
|
pci_restore_state(dev);
|
||||||
return pci_enable_device(dev);
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define i801_suspend NULL
|
#define i801_suspend NULL
|
||||||
|
|
|
@ -988,15 +988,16 @@ static irqreturn_t img_i2c_isr(int irq, void *dev_id)
|
||||||
static int img_i2c_reset_bus(struct img_i2c *i2c)
|
static int img_i2c_reset_bus(struct img_i2c *i2c)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
unsigned long time_left;
|
||||||
|
|
||||||
spin_lock_irqsave(&i2c->lock, flags);
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
reinit_completion(&i2c->msg_complete);
|
reinit_completion(&i2c->msg_complete);
|
||||||
img_i2c_reset_start(i2c);
|
img_i2c_reset_start(i2c);
|
||||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&i2c->msg_complete, IMG_I2C_TIMEOUT);
|
time_left = wait_for_completion_timeout(&i2c->msg_complete,
|
||||||
if (ret == 0)
|
IMG_I2C_TIMEOUT);
|
||||||
|
if (time_left == 0)
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1007,6 +1008,7 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||||
struct img_i2c *i2c = i2c_get_adapdata(adap);
|
struct img_i2c *i2c = i2c_get_adapdata(adap);
|
||||||
bool atomic = false;
|
bool atomic = false;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
unsigned long time_left;
|
||||||
|
|
||||||
if (i2c->mode == MODE_SUSPEND) {
|
if (i2c->mode == MODE_SUSPEND) {
|
||||||
WARN(1, "refusing to service transaction in suspended state\n");
|
WARN(1, "refusing to service transaction in suspended state\n");
|
||||||
|
@ -1068,11 +1070,11 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||||
img_i2c_write(i2c);
|
img_i2c_write(i2c);
|
||||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&i2c->msg_complete,
|
time_left = wait_for_completion_timeout(&i2c->msg_complete,
|
||||||
IMG_I2C_TIMEOUT);
|
IMG_I2C_TIMEOUT);
|
||||||
del_timer_sync(&i2c->check_timer);
|
del_timer_sync(&i2c->check_timer);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (time_left == 0) {
|
||||||
dev_err(adap->dev.parent, "i2c transfer timed out\n");
|
dev_err(adap->dev.parent, "i2c transfer timed out\n");
|
||||||
i2c->msg_status = -ETIMEDOUT;
|
i2c->msg_status = -ETIMEDOUT;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -601,6 +601,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
|
||||||
struct i2c_msg *msgs)
|
struct i2c_msg *msgs)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
unsigned long time_left;
|
||||||
unsigned int temp = 0;
|
unsigned int temp = 0;
|
||||||
unsigned long orig_jiffies = jiffies;
|
unsigned long orig_jiffies = jiffies;
|
||||||
struct imx_i2c_dma *dma = i2c_imx->dma;
|
struct imx_i2c_dma *dma = i2c_imx->dma;
|
||||||
|
@ -624,10 +625,10 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
|
||||||
*/
|
*/
|
||||||
imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
|
imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
|
||||||
reinit_completion(&i2c_imx->dma->cmd_complete);
|
reinit_completion(&i2c_imx->dma->cmd_complete);
|
||||||
result = wait_for_completion_timeout(
|
time_left = wait_for_completion_timeout(
|
||||||
&i2c_imx->dma->cmd_complete,
|
&i2c_imx->dma->cmd_complete,
|
||||||
msecs_to_jiffies(DMA_TIMEOUT));
|
msecs_to_jiffies(DMA_TIMEOUT));
|
||||||
if (result == 0) {
|
if (time_left == 0) {
|
||||||
dmaengine_terminate_all(dma->chan_using);
|
dmaengine_terminate_all(dma->chan_using);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
@ -663,6 +664,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
|
||||||
struct i2c_msg *msgs, bool is_lastmsg)
|
struct i2c_msg *msgs, bool is_lastmsg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
unsigned long time_left;
|
||||||
unsigned int temp;
|
unsigned int temp;
|
||||||
unsigned long orig_jiffies = jiffies;
|
unsigned long orig_jiffies = jiffies;
|
||||||
struct imx_i2c_dma *dma = i2c_imx->dma;
|
struct imx_i2c_dma *dma = i2c_imx->dma;
|
||||||
|
@ -682,10 +684,10 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
reinit_completion(&i2c_imx->dma->cmd_complete);
|
reinit_completion(&i2c_imx->dma->cmd_complete);
|
||||||
result = wait_for_completion_timeout(
|
time_left = wait_for_completion_timeout(
|
||||||
&i2c_imx->dma->cmd_complete,
|
&i2c_imx->dma->cmd_complete,
|
||||||
msecs_to_jiffies(DMA_TIMEOUT));
|
msecs_to_jiffies(DMA_TIMEOUT));
|
||||||
if (result == 0) {
|
if (time_left == 0) {
|
||||||
dmaengine_terminate_all(dma->chan_using);
|
dmaengine_terminate_all(dma->chan_using);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,6 +380,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
|
||||||
int size, union i2c_smbus_data *data)
|
int size, union i2c_smbus_data *data)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned long time_left;
|
||||||
dma_addr_t dma_addr = 0; /* address of the data buffer */
|
dma_addr_t dma_addr = 0; /* address of the data buffer */
|
||||||
u8 dma_size = 0;
|
u8 dma_size = 0;
|
||||||
enum dma_data_direction dma_direction = 0;
|
enum dma_data_direction dma_direction = 0;
|
||||||
|
@ -578,13 +579,13 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
|
||||||
ismt_submit_desc(priv);
|
ismt_submit_desc(priv);
|
||||||
|
|
||||||
/* Now we wait for interrupt completion, 1s */
|
/* Now we wait for interrupt completion, 1s */
|
||||||
ret = wait_for_completion_timeout(&priv->cmp, HZ*1);
|
time_left = wait_for_completion_timeout(&priv->cmp, HZ*1);
|
||||||
|
|
||||||
/* unmap the data buffer */
|
/* unmap the data buffer */
|
||||||
if (dma_size != 0)
|
if (dma_size != 0)
|
||||||
dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction);
|
dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction);
|
||||||
|
|
||||||
if (unlikely(!ret)) {
|
if (unlikely(!time_left)) {
|
||||||
dev_err(dev, "completion wait timed out\n");
|
dev_err(dev, "completion wait timed out\n");
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -0,0 +1,832 @@
|
||||||
|
/*
|
||||||
|
* Ingenic JZ4780 I2C bus driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
|
||||||
|
* Copyright (C) 2015 Imagination Technologies
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
|
||||||
|
#define JZ4780_I2C_CTRL 0x00
|
||||||
|
#define JZ4780_I2C_TAR 0x04
|
||||||
|
#define JZ4780_I2C_SAR 0x08
|
||||||
|
#define JZ4780_I2C_DC 0x10
|
||||||
|
#define JZ4780_I2C_SHCNT 0x14
|
||||||
|
#define JZ4780_I2C_SLCNT 0x18
|
||||||
|
#define JZ4780_I2C_FHCNT 0x1C
|
||||||
|
#define JZ4780_I2C_FLCNT 0x20
|
||||||
|
#define JZ4780_I2C_INTST 0x2C
|
||||||
|
#define JZ4780_I2C_INTM 0x30
|
||||||
|
#define JZ4780_I2C_RXTL 0x38
|
||||||
|
#define JZ4780_I2C_TXTL 0x3C
|
||||||
|
#define JZ4780_I2C_CINTR 0x40
|
||||||
|
#define JZ4780_I2C_CRXUF 0x44
|
||||||
|
#define JZ4780_I2C_CRXOF 0x48
|
||||||
|
#define JZ4780_I2C_CTXOF 0x4C
|
||||||
|
#define JZ4780_I2C_CRXREQ 0x50
|
||||||
|
#define JZ4780_I2C_CTXABRT 0x54
|
||||||
|
#define JZ4780_I2C_CRXDONE 0x58
|
||||||
|
#define JZ4780_I2C_CACT 0x5C
|
||||||
|
#define JZ4780_I2C_CSTP 0x60
|
||||||
|
#define JZ4780_I2C_CSTT 0x64
|
||||||
|
#define JZ4780_I2C_CGC 0x68
|
||||||
|
#define JZ4780_I2C_ENB 0x6C
|
||||||
|
#define JZ4780_I2C_STA 0x70
|
||||||
|
#define JZ4780_I2C_TXABRT 0x80
|
||||||
|
#define JZ4780_I2C_DMACR 0x88
|
||||||
|
#define JZ4780_I2C_DMATDLR 0x8C
|
||||||
|
#define JZ4780_I2C_DMARDLR 0x90
|
||||||
|
#define JZ4780_I2C_SDASU 0x94
|
||||||
|
#define JZ4780_I2C_ACKGC 0x98
|
||||||
|
#define JZ4780_I2C_ENSTA 0x9C
|
||||||
|
#define JZ4780_I2C_SDAHD 0xD0
|
||||||
|
|
||||||
|
#define JZ4780_I2C_CTRL_STPHLD BIT(7)
|
||||||
|
#define JZ4780_I2C_CTRL_SLVDIS BIT(6)
|
||||||
|
#define JZ4780_I2C_CTRL_REST BIT(5)
|
||||||
|
#define JZ4780_I2C_CTRL_MATP BIT(4)
|
||||||
|
#define JZ4780_I2C_CTRL_SATP BIT(3)
|
||||||
|
#define JZ4780_I2C_CTRL_SPDF BIT(2)
|
||||||
|
#define JZ4780_I2C_CTRL_SPDS BIT(1)
|
||||||
|
#define JZ4780_I2C_CTRL_MD BIT(0)
|
||||||
|
|
||||||
|
#define JZ4780_I2C_STA_SLVACT BIT(6)
|
||||||
|
#define JZ4780_I2C_STA_MSTACT BIT(5)
|
||||||
|
#define JZ4780_I2C_STA_RFF BIT(4)
|
||||||
|
#define JZ4780_I2C_STA_RFNE BIT(3)
|
||||||
|
#define JZ4780_I2C_STA_TFE BIT(2)
|
||||||
|
#define JZ4780_I2C_STA_TFNF BIT(1)
|
||||||
|
#define JZ4780_I2C_STA_ACT BIT(0)
|
||||||
|
|
||||||
|
static const char * const jz4780_i2c_abrt_src[] = {
|
||||||
|
"ABRT_7B_ADDR_NOACK",
|
||||||
|
"ABRT_10ADDR1_NOACK",
|
||||||
|
"ABRT_10ADDR2_NOACK",
|
||||||
|
"ABRT_XDATA_NOACK",
|
||||||
|
"ABRT_GCALL_NOACK",
|
||||||
|
"ABRT_GCALL_READ",
|
||||||
|
"ABRT_HS_ACKD",
|
||||||
|
"SBYTE_ACKDET",
|
||||||
|
"ABRT_HS_NORSTRT",
|
||||||
|
"SBYTE_NORSTRT",
|
||||||
|
"ABRT_10B_RD_NORSTRT",
|
||||||
|
"ABRT_MASTER_DIS",
|
||||||
|
"ARB_LOST",
|
||||||
|
"SLVFLUSH_TXFIFO",
|
||||||
|
"SLV_ARBLOST",
|
||||||
|
"SLVRD_INTX",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define JZ4780_I2C_INTST_IGC BIT(11)
|
||||||
|
#define JZ4780_I2C_INTST_ISTT BIT(10)
|
||||||
|
#define JZ4780_I2C_INTST_ISTP BIT(9)
|
||||||
|
#define JZ4780_I2C_INTST_IACT BIT(8)
|
||||||
|
#define JZ4780_I2C_INTST_RXDN BIT(7)
|
||||||
|
#define JZ4780_I2C_INTST_TXABT BIT(6)
|
||||||
|
#define JZ4780_I2C_INTST_RDREQ BIT(5)
|
||||||
|
#define JZ4780_I2C_INTST_TXEMP BIT(4)
|
||||||
|
#define JZ4780_I2C_INTST_TXOF BIT(3)
|
||||||
|
#define JZ4780_I2C_INTST_RXFL BIT(2)
|
||||||
|
#define JZ4780_I2C_INTST_RXOF BIT(1)
|
||||||
|
#define JZ4780_I2C_INTST_RXUF BIT(0)
|
||||||
|
|
||||||
|
#define JZ4780_I2C_INTM_MIGC BIT(11)
|
||||||
|
#define JZ4780_I2C_INTM_MISTT BIT(10)
|
||||||
|
#define JZ4780_I2C_INTM_MISTP BIT(9)
|
||||||
|
#define JZ4780_I2C_INTM_MIACT BIT(8)
|
||||||
|
#define JZ4780_I2C_INTM_MRXDN BIT(7)
|
||||||
|
#define JZ4780_I2C_INTM_MTXABT BIT(6)
|
||||||
|
#define JZ4780_I2C_INTM_MRDREQ BIT(5)
|
||||||
|
#define JZ4780_I2C_INTM_MTXEMP BIT(4)
|
||||||
|
#define JZ4780_I2C_INTM_MTXOF BIT(3)
|
||||||
|
#define JZ4780_I2C_INTM_MRXFL BIT(2)
|
||||||
|
#define JZ4780_I2C_INTM_MRXOF BIT(1)
|
||||||
|
#define JZ4780_I2C_INTM_MRXUF BIT(0)
|
||||||
|
|
||||||
|
#define JZ4780_I2C_DC_READ BIT(8)
|
||||||
|
|
||||||
|
#define JZ4780_I2C_SDAHD_HDENB BIT(8)
|
||||||
|
|
||||||
|
#define JZ4780_I2C_ENB_I2C BIT(0)
|
||||||
|
|
||||||
|
#define JZ4780_I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
|
||||||
|
#define JZ4780_I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
|
||||||
|
#define JZ4780_I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
|
||||||
|
#define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
|
||||||
|
|
||||||
|
#define JZ4780_I2C_FIFO_LEN 16
|
||||||
|
#define TX_LEVEL 3
|
||||||
|
#define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1)
|
||||||
|
|
||||||
|
#define JZ4780_I2C_TIMEOUT 300
|
||||||
|
|
||||||
|
#define BUFSIZE 200
|
||||||
|
|
||||||
|
struct jz4780_i2c {
|
||||||
|
void __iomem *iomem;
|
||||||
|
int irq;
|
||||||
|
struct clk *clk;
|
||||||
|
struct i2c_adapter adap;
|
||||||
|
|
||||||
|
/* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
|
||||||
|
spinlock_t lock;
|
||||||
|
|
||||||
|
/* beginning of lock scope */
|
||||||
|
unsigned char *rbuf;
|
||||||
|
int rd_total_len;
|
||||||
|
int rd_data_xfered;
|
||||||
|
int rd_cmd_xfered;
|
||||||
|
|
||||||
|
unsigned char *wbuf;
|
||||||
|
int wt_len;
|
||||||
|
|
||||||
|
int is_write;
|
||||||
|
int stop_hold;
|
||||||
|
int speed;
|
||||||
|
|
||||||
|
int data_buf[BUFSIZE];
|
||||||
|
int cmd_buf[BUFSIZE];
|
||||||
|
int cmd;
|
||||||
|
|
||||||
|
/* end of lock scope */
|
||||||
|
struct completion trans_waitq;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline unsigned short jz4780_i2c_readw(struct jz4780_i2c *i2c,
|
||||||
|
unsigned long offset)
|
||||||
|
{
|
||||||
|
return readw(i2c->iomem + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void jz4780_i2c_writew(struct jz4780_i2c *i2c,
|
||||||
|
unsigned long offset, unsigned short val)
|
||||||
|
{
|
||||||
|
writew(val, i2c->iomem + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_disable(struct jz4780_i2c *i2c)
|
||||||
|
{
|
||||||
|
unsigned short regval;
|
||||||
|
unsigned long loops = 5;
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 0);
|
||||||
|
|
||||||
|
do {
|
||||||
|
regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
|
||||||
|
if (!(regval & JZ4780_I2C_ENB_I2C))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
usleep_range(5000, 15000);
|
||||||
|
} while (--loops);
|
||||||
|
|
||||||
|
dev_err(&i2c->adap.dev, "disable failed: ENSTA=0x%04x\n", regval);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_enable(struct jz4780_i2c *i2c)
|
||||||
|
{
|
||||||
|
unsigned short regval;
|
||||||
|
unsigned long loops = 5;
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 1);
|
||||||
|
|
||||||
|
do {
|
||||||
|
regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
|
||||||
|
if (regval & JZ4780_I2C_ENB_I2C)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
usleep_range(5000, 15000);
|
||||||
|
} while (--loops);
|
||||||
|
|
||||||
|
dev_err(&i2c->adap.dev, "enable failed: ENSTA=0x%04x\n", regval);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address)
|
||||||
|
{
|
||||||
|
unsigned short regval;
|
||||||
|
unsigned long loops = 5;
|
||||||
|
|
||||||
|
do {
|
||||||
|
regval = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||||
|
if ((regval & JZ4780_I2C_STA_TFE) &&
|
||||||
|
!(regval & JZ4780_I2C_STA_MSTACT))
|
||||||
|
break;
|
||||||
|
|
||||||
|
usleep_range(5000, 15000);
|
||||||
|
} while (--loops);
|
||||||
|
|
||||||
|
if (loops) {
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_TAR, address);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(&i2c->adap.dev,
|
||||||
|
"set device to address 0x%02x failed, STA=0x%04x\n",
|
||||||
|
address, regval);
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
|
||||||
|
{
|
||||||
|
int dev_clk_khz = clk_get_rate(i2c->clk) / 1000;
|
||||||
|
int cnt_high = 0; /* HIGH period count of the SCL clock */
|
||||||
|
int cnt_low = 0; /* LOW period count of the SCL clock */
|
||||||
|
int cnt_period = 0; /* period count of the SCL clock */
|
||||||
|
int setup_time = 0;
|
||||||
|
int hold_time = 0;
|
||||||
|
unsigned short tmp = 0;
|
||||||
|
int i2c_clk = i2c->speed;
|
||||||
|
|
||||||
|
if (jz4780_i2c_disable(i2c))
|
||||||
|
dev_dbg(&i2c->adap.dev, "i2c not disabled\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1 JZ4780_I2C cycle equals to cnt_period PCLK(i2c_clk)
|
||||||
|
* standard mode, min LOW and HIGH period are 4700 ns and 4000 ns
|
||||||
|
* fast mode, min LOW and HIGH period are 1300 ns and 600 ns
|
||||||
|
*/
|
||||||
|
cnt_period = dev_clk_khz / i2c_clk;
|
||||||
|
|
||||||
|
if (i2c_clk <= 100)
|
||||||
|
cnt_high = (cnt_period * 4000) / (4700 + 4000);
|
||||||
|
else
|
||||||
|
cnt_high = (cnt_period * 600) / (1300 + 600);
|
||||||
|
|
||||||
|
cnt_low = cnt_period - cnt_high;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: JZ4780_I2C_CTRL_REST can't set when i2c enabled, because
|
||||||
|
* normal read are 2 messages, we cannot disable i2c controller
|
||||||
|
* between these two messages, this means that we must always set
|
||||||
|
* JZ4780_I2C_CTRL_REST when init JZ4780_I2C_CTRL
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (i2c_clk <= 100) {
|
||||||
|
tmp = JZ4780_I2C_CTRL_SPDS | JZ4780_I2C_CTRL_REST
|
||||||
|
| JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_SHCNT,
|
||||||
|
JZ4780_I2CSHCNT_ADJUST(cnt_high));
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_SLCNT,
|
||||||
|
JZ4780_I2CSLCNT_ADJUST(cnt_low));
|
||||||
|
} else {
|
||||||
|
tmp = JZ4780_I2C_CTRL_SPDF | JZ4780_I2C_CTRL_REST
|
||||||
|
| JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_FHCNT,
|
||||||
|
JZ4780_I2CFHCNT_ADJUST(cnt_high));
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_FLCNT,
|
||||||
|
JZ4780_I2CFLCNT_ADJUST(cnt_low));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a i2c device must internally provide a hold time at least 300ns
|
||||||
|
* tHD:DAT
|
||||||
|
* Standard Mode: min=300ns, max=3450ns
|
||||||
|
* Fast Mode: min=0ns, max=900ns
|
||||||
|
* tSU:DAT
|
||||||
|
* Standard Mode: min=250ns, max=infinite
|
||||||
|
* Fast Mode: min=100(250ns is recommended), max=infinite
|
||||||
|
*
|
||||||
|
* 1i2c_clk = 10^6 / dev_clk_khz
|
||||||
|
* on FPGA, dev_clk_khz = 12000, so 1i2c_clk = 1000/12 = 83ns
|
||||||
|
* on Pisces(1008M), dev_clk_khz=126000, so 1i2c_clk = 1000 / 126 = 8ns
|
||||||
|
*
|
||||||
|
* The actual hold time is (SDAHD + 1) * (i2c_clk period).
|
||||||
|
*
|
||||||
|
* Length of setup time calculated using (SDASU - 1) * (ic_clk_period)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (i2c_clk <= 100) { /* standard mode */
|
||||||
|
setup_time = 300;
|
||||||
|
hold_time = 400;
|
||||||
|
} else {
|
||||||
|
setup_time = 450;
|
||||||
|
hold_time = 450;
|
||||||
|
}
|
||||||
|
|
||||||
|
hold_time = ((hold_time * dev_clk_khz) / 1000000) - 1;
|
||||||
|
setup_time = ((setup_time * dev_clk_khz) / 1000000) + 1;
|
||||||
|
|
||||||
|
if (setup_time > 255)
|
||||||
|
setup_time = 255;
|
||||||
|
|
||||||
|
if (setup_time <= 0)
|
||||||
|
setup_time = 1;
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_SDASU, setup_time);
|
||||||
|
|
||||||
|
if (hold_time > 255)
|
||||||
|
hold_time = 255;
|
||||||
|
|
||||||
|
if (hold_time >= 0) {
|
||||||
|
/*i2c hold time enable */
|
||||||
|
hold_time |= JZ4780_I2C_SDAHD_HDENB;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
|
||||||
|
} else {
|
||||||
|
/* disable hold time */
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned short tmp;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
|
||||||
|
/* can send stop now if need */
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
|
||||||
|
/* disable all interrupts first */
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
|
||||||
|
|
||||||
|
/* then clear all interrupts */
|
||||||
|
jz4780_i2c_readw(i2c, JZ4780_I2C_CTXABRT);
|
||||||
|
jz4780_i2c_readw(i2c, JZ4780_I2C_CINTR);
|
||||||
|
|
||||||
|
/* then disable the controller */
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
|
tmp &= ~JZ4780_I2C_ENB_I2C;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
udelay(10);
|
||||||
|
tmp |= JZ4780_I2C_ENB_I2C;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
|
||||||
|
ret = jz4780_i2c_disable(i2c);
|
||||||
|
if (ret)
|
||||||
|
dev_err(&i2c->adap.dev,
|
||||||
|
"unable to disable device during cleanup!\n");
|
||||||
|
|
||||||
|
if (unlikely(jz4780_i2c_readw(i2c, JZ4780_I2C_INTM)
|
||||||
|
& jz4780_i2c_readw(i2c, JZ4780_I2C_INTST)))
|
||||||
|
dev_err(&i2c->adap.dev,
|
||||||
|
"device has interrupts after a complete cleanup!\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_prepare(struct jz4780_i2c *i2c)
|
||||||
|
{
|
||||||
|
jz4780_i2c_set_speed(i2c);
|
||||||
|
return jz4780_i2c_enable(i2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cmd_count; i++)
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4780_i2c_trans_done(struct jz4780_i2c *i2c)
|
||||||
|
{
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
|
||||||
|
complete(&i2c->trans_waitq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
|
||||||
|
{
|
||||||
|
unsigned short tmp;
|
||||||
|
unsigned short intst;
|
||||||
|
unsigned short intmsk;
|
||||||
|
struct jz4780_i2c *i2c = dev_id;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
|
||||||
|
intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST);
|
||||||
|
|
||||||
|
intst &= intmsk;
|
||||||
|
|
||||||
|
if (intst & JZ4780_I2C_INTST_TXABT) {
|
||||||
|
jz4780_i2c_trans_done(i2c);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intst & JZ4780_I2C_INTST_RXOF) {
|
||||||
|
dev_dbg(&i2c->adap.dev, "received fifo overflow!\n");
|
||||||
|
jz4780_i2c_trans_done(i2c);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When reading, always drain RX FIFO before we send more Read
|
||||||
|
* Commands to avoid fifo overrun
|
||||||
|
*/
|
||||||
|
if (i2c->is_write == 0) {
|
||||||
|
int rd_left;
|
||||||
|
|
||||||
|
while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA)
|
||||||
|
& JZ4780_I2C_STA_RFNE)) {
|
||||||
|
*(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC)
|
||||||
|
& 0xff;
|
||||||
|
i2c->rd_data_xfered++;
|
||||||
|
if (i2c->rd_data_xfered == i2c->rd_total_len) {
|
||||||
|
jz4780_i2c_trans_done(i2c);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rd_left = i2c->rd_total_len - i2c->rd_data_xfered;
|
||||||
|
|
||||||
|
if (rd_left <= JZ4780_I2C_FIFO_LEN)
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intst & JZ4780_I2C_INTST_TXEMP) {
|
||||||
|
if (i2c->is_write == 0) {
|
||||||
|
int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
|
||||||
|
int max_send = (JZ4780_I2C_FIFO_LEN - 1)
|
||||||
|
- (i2c->rd_cmd_xfered
|
||||||
|
- i2c->rd_data_xfered);
|
||||||
|
int cmd_to_send = min(cmd_left, max_send);
|
||||||
|
|
||||||
|
if (i2c->rd_cmd_xfered != 0)
|
||||||
|
cmd_to_send = min(cmd_to_send,
|
||||||
|
JZ4780_I2C_FIFO_LEN
|
||||||
|
- TX_LEVEL - 1);
|
||||||
|
|
||||||
|
if (cmd_to_send) {
|
||||||
|
jz4780_i2c_send_rcmd(i2c, cmd_to_send);
|
||||||
|
i2c->rd_cmd_xfered += cmd_to_send;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
|
||||||
|
if (cmd_left == 0) {
|
||||||
|
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
|
||||||
|
intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
|
||||||
|
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned short data;
|
||||||
|
unsigned short i2c_sta;
|
||||||
|
|
||||||
|
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||||
|
|
||||||
|
while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
|
||||||
|
(i2c->wt_len > 0)) {
|
||||||
|
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||||
|
data = *i2c->wbuf;
|
||||||
|
data &= ~JZ4780_I2C_DC_READ;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
|
||||||
|
data);
|
||||||
|
i2c->wbuf++;
|
||||||
|
i2c->wt_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2c->wt_len == 0) {
|
||||||
|
if (!i2c->stop_hold) {
|
||||||
|
tmp = jz4780_i2c_readw(i2c,
|
||||||
|
JZ4780_I2C_CTRL);
|
||||||
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL,
|
||||||
|
tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
jz4780_i2c_trans_done(i2c);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src);
|
||||||
|
dev_err(&i2c->adap.dev, "device addr=%x\n",
|
||||||
|
jz4780_i2c_readw(i2c, JZ4780_I2C_TAR));
|
||||||
|
dev_err(&i2c->adap.dev, "send cmd count:%d %d\n",
|
||||||
|
i2c->cmd, i2c->cmd_buf[i2c->cmd]);
|
||||||
|
dev_err(&i2c->adap.dev, "receive data count:%d %d\n",
|
||||||
|
i2c->cmd, i2c->data_buf[i2c->cmd]);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
if (src & BIT(i))
|
||||||
|
dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n",
|
||||||
|
i, jz4780_i2c_abrt_src[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
|
||||||
|
unsigned char *buf, int len, int cnt,
|
||||||
|
int idx)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
long timeout;
|
||||||
|
int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
|
||||||
|
unsigned short tmp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
memset(buf, 0, len);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
|
||||||
|
i2c->stop_hold = 0;
|
||||||
|
i2c->is_write = 0;
|
||||||
|
i2c->rbuf = buf;
|
||||||
|
i2c->rd_total_len = len;
|
||||||
|
i2c->rd_data_xfered = 0;
|
||||||
|
i2c->rd_cmd_xfered = 0;
|
||||||
|
|
||||||
|
if (len <= JZ4780_I2C_FIFO_LEN)
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1);
|
||||||
|
else
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL);
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM,
|
||||||
|
JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
|
||||||
|
| JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
|
||||||
|
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
|
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
|
||||||
|
timeout = wait_for_completion_timeout(&i2c->trans_waitq,
|
||||||
|
msecs_to_jiffies(wait_time));
|
||||||
|
|
||||||
|
if (!timeout) {
|
||||||
|
dev_err(&i2c->adap.dev, "irq read timeout\n");
|
||||||
|
dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n",
|
||||||
|
i2c->cmd, i2c->cmd_buf[i2c->cmd]);
|
||||||
|
dev_dbg(&i2c->adap.dev, "receive data count:%d %d\n",
|
||||||
|
i2c->cmd, i2c->data_buf[i2c->cmd]);
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
|
||||||
|
if (tmp) {
|
||||||
|
jz4780_i2c_txabrt(i2c, tmp);
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
|
||||||
|
unsigned char *buf, int len,
|
||||||
|
int cnt, int idx)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
|
||||||
|
long timeout;
|
||||||
|
unsigned short tmp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
|
||||||
|
if (idx < (cnt - 1))
|
||||||
|
i2c->stop_hold = 1;
|
||||||
|
else
|
||||||
|
i2c->stop_hold = 0;
|
||||||
|
|
||||||
|
i2c->is_write = 1;
|
||||||
|
i2c->wbuf = buf;
|
||||||
|
i2c->wt_len = len;
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP
|
||||||
|
| JZ4780_I2C_INTM_MTXABT);
|
||||||
|
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
|
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
|
||||||
|
timeout = wait_for_completion_timeout(&i2c->trans_waitq,
|
||||||
|
msecs_to_jiffies(wait_time));
|
||||||
|
if (timeout && !i2c->stop_hold) {
|
||||||
|
unsigned short i2c_sta;
|
||||||
|
int write_in_process;
|
||||||
|
|
||||||
|
timeout = JZ4780_I2C_TIMEOUT * 100;
|
||||||
|
for (; timeout > 0; timeout--) {
|
||||||
|
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||||
|
|
||||||
|
write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) ||
|
||||||
|
!(i2c_sta & JZ4780_I2C_STA_TFE);
|
||||||
|
if (!write_in_process)
|
||||||
|
break;
|
||||||
|
udelay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timeout) {
|
||||||
|
dev_err(&i2c->adap.dev, "write wait timeout\n");
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
|
||||||
|
if (tmp) {
|
||||||
|
jz4780_i2c_txabrt(i2c, tmp);
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||||
|
int count)
|
||||||
|
{
|
||||||
|
int i = -EIO;
|
||||||
|
int ret = 0;
|
||||||
|
struct jz4780_i2c *i2c = adap->algo_data;
|
||||||
|
|
||||||
|
ret = jz4780_i2c_prepare(i2c);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&i2c->adap.dev, "I2C prepare failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->addr != jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)) {
|
||||||
|
ret = jz4780_i2c_set_target(i2c, msg->addr);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (i = 0; i < count; i++, msg++) {
|
||||||
|
if (msg->flags & I2C_M_RD)
|
||||||
|
ret = jz4780_i2c_xfer_read(i2c, msg->buf, msg->len,
|
||||||
|
count, i);
|
||||||
|
else
|
||||||
|
ret = jz4780_i2c_xfer_write(i2c, msg->buf, msg->len,
|
||||||
|
count, i);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i;
|
||||||
|
|
||||||
|
out:
|
||||||
|
jz4780_i2c_cleanup(i2c);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 jz4780_i2c_functionality(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_algorithm jz4780_i2c_algorithm = {
|
||||||
|
.master_xfer = jz4780_i2c_xfer,
|
||||||
|
.functionality = jz4780_i2c_functionality,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id jz4780_i2c_of_matches[] = {
|
||||||
|
{ .compatible = "ingenic,jz4780-i2c", },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz4780_i2c_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int clk_freq = 0;
|
||||||
|
unsigned short tmp;
|
||||||
|
struct resource *r;
|
||||||
|
struct jz4780_i2c *i2c;
|
||||||
|
|
||||||
|
i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL);
|
||||||
|
if (!i2c)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
i2c->adap.owner = THIS_MODULE;
|
||||||
|
i2c->adap.algo = &jz4780_i2c_algorithm;
|
||||||
|
i2c->adap.algo_data = i2c;
|
||||||
|
i2c->adap.retries = 5;
|
||||||
|
i2c->adap.dev.parent = &pdev->dev;
|
||||||
|
i2c->adap.dev.of_node = pdev->dev.of_node;
|
||||||
|
sprintf(i2c->adap.name, "%s", pdev->name);
|
||||||
|
|
||||||
|
init_completion(&i2c->trans_waitq);
|
||||||
|
spin_lock_init(&i2c->lock);
|
||||||
|
|
||||||
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
i2c->iomem = devm_ioremap_resource(&pdev->dev, r);
|
||||||
|
if (IS_ERR(i2c->iomem))
|
||||||
|
return PTR_ERR(i2c->iomem);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, i2c);
|
||||||
|
|
||||||
|
i2c->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(i2c->clk))
|
||||||
|
return PTR_ERR(i2c->clk);
|
||||||
|
|
||||||
|
clk_prepare_enable(i2c->clk);
|
||||||
|
|
||||||
|
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||||
|
&clk_freq)) {
|
||||||
|
dev_err(&pdev->dev, "clock-frequency not specified in DT");
|
||||||
|
return clk_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c->speed = clk_freq / 1000;
|
||||||
|
jz4780_i2c_set_speed(i2c);
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed);
|
||||||
|
|
||||||
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
|
||||||
|
|
||||||
|
i2c->cmd = 0;
|
||||||
|
memset(i2c->cmd_buf, 0, BUFSIZE);
|
||||||
|
memset(i2c->data_buf, 0, BUFSIZE);
|
||||||
|
|
||||||
|
i2c->irq = platform_get_irq(pdev, 0);
|
||||||
|
ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
|
||||||
|
dev_name(&pdev->dev), i2c);
|
||||||
|
if (ret) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_add_adapter(&i2c->adap);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to add bus\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
clk_disable_unprepare(i2c->clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4780_i2c_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct jz4780_i2c *i2c = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
clk_disable_unprepare(i2c->clk);
|
||||||
|
i2c_del_adapter(&i2c->adap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver jz4780_i2c_driver = {
|
||||||
|
.probe = jz4780_i2c_probe,
|
||||||
|
.remove = jz4780_i2c_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "jz4780-i2c",
|
||||||
|
.of_match_table = of_match_ptr(jz4780_i2c_of_matches),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(jz4780_i2c_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("ztyan<ztyan@ingenic.cn>");
|
||||||
|
MODULE_DESCRIPTION("i2c driver for JZ4780 SoCs");
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#include <asm/mpc52xx.h>
|
#include <asm/mpc52xx.h>
|
||||||
|
#include <asm/mpc85xx.h>
|
||||||
#include <sysdev/fsl_soc.h>
|
#include <sysdev/fsl_soc.h>
|
||||||
|
|
||||||
#define DRV_NAME "mpc-i2c"
|
#define DRV_NAME "mpc-i2c"
|
||||||
|
@ -95,8 +96,9 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
|
||||||
i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
|
i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
|
||||||
writeb(0, i2c->base + MPC_I2C_SR);
|
writeb(0, i2c->base + MPC_I2C_SR);
|
||||||
wake_up(&i2c->queue);
|
wake_up(&i2c->queue);
|
||||||
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
return IRQ_HANDLED;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
|
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
|
||||||
|
@ -346,6 +348,33 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 mpc_i2c_get_prescaler_8xxx(void)
|
||||||
|
{
|
||||||
|
/* mpc83xx and mpc82xx all have prescaler 1 */
|
||||||
|
u32 prescaler = 1;
|
||||||
|
|
||||||
|
/* mpc85xx */
|
||||||
|
if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2)
|
||||||
|
|| pvr_version_is(PVR_VER_E500MC)
|
||||||
|
|| pvr_version_is(PVR_VER_E5500)
|
||||||
|
|| pvr_version_is(PVR_VER_E6500)) {
|
||||||
|
unsigned int svr = mfspr(SPRN_SVR);
|
||||||
|
|
||||||
|
if ((SVR_SOC_VER(svr) == SVR_8540)
|
||||||
|
|| (SVR_SOC_VER(svr) == SVR_8541)
|
||||||
|
|| (SVR_SOC_VER(svr) == SVR_8560)
|
||||||
|
|| (SVR_SOC_VER(svr) == SVR_8555)
|
||||||
|
|| (SVR_SOC_VER(svr) == SVR_8610))
|
||||||
|
/* the above 85xx SoCs have prescaler 1 */
|
||||||
|
prescaler = 1;
|
||||||
|
else
|
||||||
|
/* all the other 85xx have prescaler 2 */
|
||||||
|
prescaler = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prescaler;
|
||||||
|
}
|
||||||
|
|
||||||
static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
|
static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
|
||||||
u32 prescaler, u32 *real_clk)
|
u32 prescaler, u32 *real_clk)
|
||||||
{
|
{
|
||||||
|
@ -363,7 +392,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
|
||||||
if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
|
if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
|
||||||
prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
|
prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
|
||||||
if (!prescaler)
|
if (!prescaler)
|
||||||
prescaler = 1;
|
prescaler = mpc_i2c_get_prescaler_8xxx();
|
||||||
|
|
||||||
divider = fsl_get_sys_freq() / clock / prescaler;
|
divider = fsl_get_sys_freq() / clock / prescaler;
|
||||||
|
|
||||||
|
|
|
@ -568,6 +568,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||||
int ret;
|
int ret;
|
||||||
int flags;
|
int flags;
|
||||||
int use_pio = 0;
|
int use_pio = 0;
|
||||||
|
unsigned long time_left;
|
||||||
|
|
||||||
flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
|
flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
|
||||||
|
|
||||||
|
@ -599,9 +600,9 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&i2c->cmd_complete,
|
time_left = wait_for_completion_timeout(&i2c->cmd_complete,
|
||||||
msecs_to_jiffies(1000));
|
msecs_to_jiffies(1000));
|
||||||
if (ret == 0)
|
if (!time_left)
|
||||||
goto timeout;
|
goto timeout;
|
||||||
|
|
||||||
ret = i2c->cmd_err;
|
ret = i2c->cmd_err;
|
||||||
|
|
|
@ -446,9 +446,9 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
|
||||||
*/
|
*/
|
||||||
static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
|
static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
|
||||||
{
|
{
|
||||||
u32 status = 0;
|
int status = 0;
|
||||||
u32 mcr, irq_mask;
|
u32 mcr, irq_mask;
|
||||||
int timeout;
|
unsigned long timeout;
|
||||||
|
|
||||||
mcr = load_i2c_mcr_reg(dev, flags);
|
mcr = load_i2c_mcr_reg(dev, flags);
|
||||||
writel(mcr, dev->virtbase + I2C_MCR);
|
writel(mcr, dev->virtbase + I2C_MCR);
|
||||||
|
@ -517,7 +517,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
|
||||||
{
|
{
|
||||||
u32 status = 0;
|
u32 status = 0;
|
||||||
u32 mcr, irq_mask;
|
u32 mcr, irq_mask;
|
||||||
int timeout;
|
unsigned long timeout;
|
||||||
|
|
||||||
mcr = load_i2c_mcr_reg(dev, flags);
|
mcr = load_i2c_mcr_reg(dev, flags);
|
||||||
|
|
||||||
|
|
|
@ -104,18 +104,8 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||||
req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
|
req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* For two messages, we basically support only simple
|
req.type = (msgs[1].flags & I2C_M_RD) ?
|
||||||
* smbus transactions of a write plus a read. We might
|
OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
|
||||||
* want to allow also two writes but we'd have to bounce
|
|
||||||
* the data into a single buffer.
|
|
||||||
*/
|
|
||||||
if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
if (msgs[0].len > 4)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
if (msgs[0].addr != msgs[1].addr)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
req.type = OPAL_I2C_SM_READ;
|
|
||||||
req.addr = cpu_to_be16(msgs[0].addr);
|
req.addr = cpu_to_be16(msgs[0].addr);
|
||||||
req.subaddr_sz = msgs[0].len;
|
req.subaddr_sz = msgs[0].len;
|
||||||
for (i = 0; i < msgs[0].len; i++)
|
for (i = 0; i < msgs[0].len; i++)
|
||||||
|
@ -210,6 +200,15 @@ static const struct i2c_algorithm i2c_opal_algo = {
|
||||||
.functionality = i2c_opal_func,
|
.functionality = i2c_opal_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For two messages, we basically support simple smbus transactions of a
|
||||||
|
* write-then-anything.
|
||||||
|
*/
|
||||||
|
static struct i2c_adapter_quirks i2c_opal_quirks = {
|
||||||
|
.flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
|
||||||
|
.max_comb_1st_msg_len = 4,
|
||||||
|
};
|
||||||
|
|
||||||
static int i2c_opal_probe(struct platform_device *pdev)
|
static int i2c_opal_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter;
|
struct i2c_adapter *adapter;
|
||||||
|
@ -232,6 +231,7 @@ static int i2c_opal_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
adapter->algo = &i2c_opal_algo;
|
adapter->algo = &i2c_opal_algo;
|
||||||
adapter->algo_data = (void *)(unsigned long)opal_id;
|
adapter->algo_data = (void *)(unsigned long)opal_id;
|
||||||
|
adapter->quirks = &i2c_opal_quirks;
|
||||||
adapter->dev.parent = &pdev->dev;
|
adapter->dev.parent = &pdev->dev;
|
||||||
adapter->dev.of_node = of_node_get(pdev->dev.of_node);
|
adapter->dev.of_node = of_node_get(pdev->dev.of_node);
|
||||||
pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL);
|
pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL);
|
||||||
|
|
|
@ -456,14 +456,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
|
|
||||||
cmd->write_len > MSP_MAX_BYTES_PER_RW) {
|
|
||||||
dev_err(&pmcmsptwi_adapter.dev,
|
|
||||||
"%s: Cannot transfer more than %d bytes\n",
|
|
||||||
__func__, MSP_MAX_BYTES_PER_RW);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&data->lock);
|
mutex_lock(&data->lock);
|
||||||
dev_dbg(&pmcmsptwi_adapter.dev,
|
dev_dbg(&pmcmsptwi_adapter.dev,
|
||||||
"Setting address to 0x%04x\n", cmd->addr);
|
"Setting address to 0x%04x\n", cmd->addr);
|
||||||
|
@ -520,25 +512,14 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
|
||||||
struct pmcmsptwi_cfg oldcfg, newcfg;
|
struct pmcmsptwi_cfg oldcfg, newcfg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (num > 2) {
|
if (num == 2) {
|
||||||
dev_dbg(&adap->dev, "%d messages unsupported\n", num);
|
|
||||||
return -EINVAL;
|
|
||||||
} else if (num == 2) {
|
|
||||||
/* Check for a dual write-then-read command */
|
|
||||||
struct i2c_msg *nextmsg = msg + 1;
|
struct i2c_msg *nextmsg = msg + 1;
|
||||||
if (!(msg->flags & I2C_M_RD) &&
|
|
||||||
(nextmsg->flags & I2C_M_RD) &&
|
cmd.type = MSP_TWI_CMD_WRITE_READ;
|
||||||
msg->addr == nextmsg->addr) {
|
cmd.write_len = msg->len;
|
||||||
cmd.type = MSP_TWI_CMD_WRITE_READ;
|
cmd.write_data = msg->buf;
|
||||||
cmd.write_len = msg->len;
|
cmd.read_len = nextmsg->len;
|
||||||
cmd.write_data = msg->buf;
|
cmd.read_data = nextmsg->buf;
|
||||||
cmd.read_len = nextmsg->len;
|
|
||||||
cmd.read_data = nextmsg->buf;
|
|
||||||
} else {
|
|
||||||
dev_dbg(&adap->dev,
|
|
||||||
"Non write-read dual messages unsupported\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
} else if (msg->flags & I2C_M_RD) {
|
} else if (msg->flags & I2C_M_RD) {
|
||||||
cmd.type = MSP_TWI_CMD_READ;
|
cmd.type = MSP_TWI_CMD_READ;
|
||||||
cmd.read_len = msg->len;
|
cmd.read_len = msg->len;
|
||||||
|
@ -598,6 +579,14 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
|
||||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
|
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
|
||||||
|
.flags = I2C_AQ_COMB_WRITE_THEN_READ,
|
||||||
|
.max_write_len = MSP_MAX_BYTES_PER_RW,
|
||||||
|
.max_read_len = MSP_MAX_BYTES_PER_RW,
|
||||||
|
.max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW,
|
||||||
|
.max_comb_2nd_msg_len = MSP_MAX_BYTES_PER_RW,
|
||||||
|
};
|
||||||
|
|
||||||
/* -- Initialization -- */
|
/* -- Initialization -- */
|
||||||
|
|
||||||
static struct i2c_algorithm pmcmsptwi_algo = {
|
static struct i2c_algorithm pmcmsptwi_algo = {
|
||||||
|
@ -609,6 +598,7 @@ static struct i2c_adapter pmcmsptwi_adapter = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||||
.algo = &pmcmsptwi_algo,
|
.algo = &pmcmsptwi_algo,
|
||||||
|
.quirks = &pmcmsptwi_i2c_quirks,
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -153,12 +153,6 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
|
||||||
int read;
|
int read;
|
||||||
int addrdir;
|
int addrdir;
|
||||||
|
|
||||||
if (num != 1) {
|
|
||||||
dev_err(&adap->dev,
|
|
||||||
"Multi-message I2C transactions not supported\n");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msgs->flags & I2C_M_TEN)
|
if (msgs->flags & I2C_M_TEN)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
read = (msgs->flags & I2C_M_RD) != 0;
|
read = (msgs->flags & I2C_M_RD) != 0;
|
||||||
|
@ -205,6 +199,9 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
|
||||||
.functionality = i2c_powermac_func,
|
.functionality = i2c_powermac_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct i2c_adapter_quirks i2c_powermac_quirks = {
|
||||||
|
.max_num_msgs = 1,
|
||||||
|
};
|
||||||
|
|
||||||
static int i2c_powermac_remove(struct platform_device *dev)
|
static int i2c_powermac_remove(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -434,6 +431,7 @@ static int i2c_powermac_probe(struct platform_device *dev)
|
||||||
|
|
||||||
platform_set_drvdata(dev, adapter);
|
platform_set_drvdata(dev, adapter);
|
||||||
adapter->algo = &i2c_powermac_algorithm;
|
adapter->algo = &i2c_powermac_algorithm;
|
||||||
|
adapter->quirks = &i2c_powermac_quirks;
|
||||||
i2c_set_adapdata(adapter, bus);
|
i2c_set_adapdata(adapter, bus);
|
||||||
adapter->dev.parent = &dev->dev;
|
adapter->dev.parent = &dev->dev;
|
||||||
|
|
||||||
|
|
|
@ -412,17 +412,6 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
||||||
unsigned long left;
|
unsigned long left;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* The QUP block will issue a NACK and STOP on the bus when reaching
|
|
||||||
* the end of the read, the length of the read is specified as one byte
|
|
||||||
* which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
|
|
||||||
*/
|
|
||||||
if (msg->len > QUP_READ_LIMIT) {
|
|
||||||
dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
|
|
||||||
QUP_READ_LIMIT);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
qup->msg = msg;
|
qup->msg = msg;
|
||||||
qup->pos = 0;
|
qup->pos = 0;
|
||||||
|
|
||||||
|
@ -534,6 +523,15 @@ static const struct i2c_algorithm qup_i2c_algo = {
|
||||||
.functionality = qup_i2c_func,
|
.functionality = qup_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The QUP block will issue a NACK and STOP on the bus when reaching
|
||||||
|
* the end of the read, the length of the read is specified as one byte
|
||||||
|
* which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
|
||||||
|
*/
|
||||||
|
static struct i2c_adapter_quirks qup_i2c_quirks = {
|
||||||
|
.max_read_len = QUP_READ_LIMIT,
|
||||||
|
};
|
||||||
|
|
||||||
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
|
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
|
||||||
{
|
{
|
||||||
clk_prepare_enable(qup->clk);
|
clk_prepare_enable(qup->clk);
|
||||||
|
@ -670,6 +668,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
i2c_set_adapdata(&qup->adap, qup);
|
i2c_set_adapdata(&qup->adap, qup);
|
||||||
qup->adap.algo = &qup_i2c_algo;
|
qup->adap.algo = &qup_i2c_algo;
|
||||||
|
qup->adap.quirks = &qup_i2c_quirks;
|
||||||
qup->adap.dev.parent = qup->dev;
|
qup->adap.dev.parent = qup->dev;
|
||||||
qup->adap.dev.of_node = pdev->dev.of_node;
|
qup->adap.dev.of_node = pdev->dev.of_node;
|
||||||
strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
|
strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
|
||||||
|
|
|
@ -382,11 +382,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
|
||||||
if (ssr_filtered & SAR) {
|
if (ssr_filtered & SAR) {
|
||||||
/* read or write request */
|
/* read or write request */
|
||||||
if (ssr_raw & STM) {
|
if (ssr_raw & STM) {
|
||||||
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
|
i2c_slave_event(priv->slave, I2C_SLAVE_READ_REQUESTED, &value);
|
||||||
rcar_i2c_write(priv, ICRXTX, value);
|
rcar_i2c_write(priv, ICRXTX, value);
|
||||||
rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
|
rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
|
||||||
} else {
|
} else {
|
||||||
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
|
i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
|
||||||
rcar_i2c_read(priv, ICRXTX); /* dummy read */
|
rcar_i2c_read(priv, ICRXTX); /* dummy read */
|
||||||
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
|
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
|
||||||
}
|
}
|
||||||
|
@ -406,17 +406,15 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
value = rcar_i2c_read(priv, ICRXTX);
|
value = rcar_i2c_read(priv, ICRXTX);
|
||||||
ret = i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_END, &value);
|
ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
|
||||||
/* Send NACK in case of error */
|
/* Send NACK in case of error */
|
||||||
rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
|
rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
|
||||||
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
|
|
||||||
rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
|
rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* master wants to read from us */
|
/* master wants to read from us */
|
||||||
if (ssr_filtered & SDE) {
|
if (ssr_filtered & SDE) {
|
||||||
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_END, &value);
|
i2c_slave_event(priv->slave, I2C_SLAVE_READ_PROCESSED, &value);
|
||||||
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
|
|
||||||
rcar_i2c_write(priv, ICRXTX, value);
|
rcar_i2c_write(priv, ICRXTX, value);
|
||||||
rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);
|
rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);
|
||||||
}
|
}
|
||||||
|
|
|
@ -532,7 +532,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||||
{
|
{
|
||||||
u32 packet_header;
|
u32 packet_header;
|
||||||
u32 int_mask;
|
u32 int_mask;
|
||||||
int ret;
|
unsigned long time_left;
|
||||||
|
|
||||||
tegra_i2c_flush_fifos(i2c_dev);
|
tegra_i2c_flush_fifos(i2c_dev);
|
||||||
|
|
||||||
|
@ -585,18 +585,20 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||||
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
|
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
|
||||||
i2c_readl(i2c_dev, I2C_INT_MASK));
|
i2c_readl(i2c_dev, I2C_INT_MASK));
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT);
|
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||||
|
TEGRA_I2C_TIMEOUT);
|
||||||
tegra_i2c_mask_irq(i2c_dev, int_mask);
|
tegra_i2c_mask_irq(i2c_dev, int_mask);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (time_left == 0) {
|
||||||
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
||||||
|
|
||||||
tegra_i2c_init(i2c_dev);
|
tegra_i2c_init(i2c_dev);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n",
|
dev_dbg(i2c_dev->dev, "transfer complete: %lu %d %d\n",
|
||||||
ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err);
|
time_left, completion_done(&i2c_dev->msg_complete),
|
||||||
|
i2c_dev->msg_err);
|
||||||
|
|
||||||
if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
|
if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -288,10 +288,6 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
|
||||||
i, pmsg->flags & I2C_M_RD ? "read" : "write",
|
i, pmsg->flags & I2C_M_RD ? "read" : "write",
|
||||||
pmsg->flags, pmsg->len, pmsg->addr);
|
pmsg->flags, pmsg->len, pmsg->addr);
|
||||||
|
|
||||||
/* msgs longer than 2048 bytes are not supported by adapter */
|
|
||||||
if (pmsg->len > 2048)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mutex_lock(&vb->lock);
|
mutex_lock(&vb->lock);
|
||||||
/* directly send the message */
|
/* directly send the message */
|
||||||
if (pmsg->flags & I2C_M_RD) {
|
if (pmsg->flags & I2C_M_RD) {
|
||||||
|
@ -358,6 +354,11 @@ static const struct i2c_algorithm vprbrd_algorithm = {
|
||||||
.functionality = vprbrd_i2c_func,
|
.functionality = vprbrd_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct i2c_adapter_quirks vprbrd_quirks = {
|
||||||
|
.max_read_len = 2048,
|
||||||
|
.max_write_len = 2048,
|
||||||
|
};
|
||||||
|
|
||||||
static int vprbrd_i2c_probe(struct platform_device *pdev)
|
static int vprbrd_i2c_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
|
struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
@ -373,6 +374,7 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)
|
||||||
vb_i2c->i2c.owner = THIS_MODULE;
|
vb_i2c->i2c.owner = THIS_MODULE;
|
||||||
vb_i2c->i2c.class = I2C_CLASS_HWMON;
|
vb_i2c->i2c.class = I2C_CLASS_HWMON;
|
||||||
vb_i2c->i2c.algo = &vprbrd_algorithm;
|
vb_i2c->i2c.algo = &vprbrd_algorithm;
|
||||||
|
vb_i2c->i2c.quirks = &vprbrd_quirks;
|
||||||
vb_i2c->i2c.algo_data = vb;
|
vb_i2c->i2c.algo_data = vb;
|
||||||
/* save the param in usb capabable memory */
|
/* save the param in usb capabable memory */
|
||||||
vb_i2c->bus_freq_param = i2c_bus_param;
|
vb_i2c->bus_freq_param = i2c_bus_param;
|
||||||
|
|
|
@ -128,7 +128,8 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
|
||||||
{
|
{
|
||||||
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||||
u16 val, tcr_val;
|
u16 val, tcr_val;
|
||||||
int ret, wait_result;
|
int ret;
|
||||||
|
unsigned long wait_result;
|
||||||
int xfer_len = 0;
|
int xfer_len = 0;
|
||||||
|
|
||||||
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
||||||
|
@ -177,7 +178,7 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
|
||||||
|
|
||||||
while (xfer_len < pmsg->len) {
|
while (xfer_len < pmsg->len) {
|
||||||
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
|
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
|
||||||
500 * HZ / 1000);
|
msecs_to_jiffies(500));
|
||||||
|
|
||||||
if (wait_result == 0)
|
if (wait_result == 0)
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
@ -218,7 +219,8 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
|
||||||
{
|
{
|
||||||
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||||
u16 val, tcr_val;
|
u16 val, tcr_val;
|
||||||
int ret, wait_result;
|
int ret;
|
||||||
|
unsigned long wait_result;
|
||||||
u32 xfer_len = 0;
|
u32 xfer_len = 0;
|
||||||
|
|
||||||
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
||||||
|
@ -266,7 +268,7 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
|
||||||
|
|
||||||
while (xfer_len < pmsg->len) {
|
while (xfer_len < pmsg->len) {
|
||||||
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
|
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
|
||||||
500 * HZ / 1000);
|
msecs_to_jiffies(500));
|
||||||
|
|
||||||
if (!wait_result)
|
if (!wait_result)
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
|
|
@ -0,0 +1,445 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2003-2015 Broadcom Corporation
|
||||||
|
*
|
||||||
|
* This file is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2. This program is licensed "as is" without any
|
||||||
|
* warranty of any kind, whether express or implied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_DIV 0x0
|
||||||
|
#define XLP9XX_I2C_CTRL 0x1
|
||||||
|
#define XLP9XX_I2C_CMD 0x2
|
||||||
|
#define XLP9XX_I2C_STATUS 0x3
|
||||||
|
#define XLP9XX_I2C_MTXFIFO 0x4
|
||||||
|
#define XLP9XX_I2C_MRXFIFO 0x5
|
||||||
|
#define XLP9XX_I2C_MFIFOCTRL 0x6
|
||||||
|
#define XLP9XX_I2C_STXFIFO 0x7
|
||||||
|
#define XLP9XX_I2C_SRXFIFO 0x8
|
||||||
|
#define XLP9XX_I2C_SFIFOCTRL 0x9
|
||||||
|
#define XLP9XX_I2C_SLAVEADDR 0xA
|
||||||
|
#define XLP9XX_I2C_OWNADDR 0xB
|
||||||
|
#define XLP9XX_I2C_FIFOWCNT 0xC
|
||||||
|
#define XLP9XX_I2C_INTEN 0xD
|
||||||
|
#define XLP9XX_I2C_INTST 0xE
|
||||||
|
#define XLP9XX_I2C_WAITCNT 0xF
|
||||||
|
#define XLP9XX_I2C_TIMEOUT 0X10
|
||||||
|
#define XLP9XX_I2C_GENCALLADDR 0x11
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_CMD_START BIT(7)
|
||||||
|
#define XLP9XX_I2C_CMD_STOP BIT(6)
|
||||||
|
#define XLP9XX_I2C_CMD_READ BIT(5)
|
||||||
|
#define XLP9XX_I2C_CMD_WRITE BIT(4)
|
||||||
|
#define XLP9XX_I2C_CMD_ACK BIT(3)
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_CTRL_MCTLEN_SHIFT 16
|
||||||
|
#define XLP9XX_I2C_CTRL_MCTLEN_MASK 0xffff0000
|
||||||
|
#define XLP9XX_I2C_CTRL_RST BIT(8)
|
||||||
|
#define XLP9XX_I2C_CTRL_EN BIT(6)
|
||||||
|
#define XLP9XX_I2C_CTRL_MASTER BIT(4)
|
||||||
|
#define XLP9XX_I2C_CTRL_FIFORD BIT(1)
|
||||||
|
#define XLP9XX_I2C_CTRL_ADDMODE BIT(0)
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_INTEN_NACKADDR BIT(25)
|
||||||
|
#define XLP9XX_I2C_INTEN_SADDR BIT(13)
|
||||||
|
#define XLP9XX_I2C_INTEN_DATADONE BIT(12)
|
||||||
|
#define XLP9XX_I2C_INTEN_ARLOST BIT(11)
|
||||||
|
#define XLP9XX_I2C_INTEN_MFIFOFULL BIT(4)
|
||||||
|
#define XLP9XX_I2C_INTEN_MFIFOEMTY BIT(3)
|
||||||
|
#define XLP9XX_I2C_INTEN_MFIFOHI BIT(2)
|
||||||
|
#define XLP9XX_I2C_INTEN_BUSERR BIT(0)
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT 8
|
||||||
|
#define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT 0
|
||||||
|
#define XLP9XX_I2C_MFIFOCTRL_RST BIT(16)
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_SLAVEADDR_RW BIT(0)
|
||||||
|
#define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT 1
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_IP_CLK_FREQ 133000000UL
|
||||||
|
#define XLP9XX_I2C_DEFAULT_FREQ 100000
|
||||||
|
#define XLP9XX_I2C_HIGH_FREQ 400000
|
||||||
|
#define XLP9XX_I2C_FIFO_SIZE 0x80U
|
||||||
|
#define XLP9XX_I2C_TIMEOUT_MS 1000
|
||||||
|
|
||||||
|
#define XLP9XX_I2C_FIFO_WCNT_MASK 0xff
|
||||||
|
#define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \
|
||||||
|
XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR)
|
||||||
|
|
||||||
|
struct xlp9xx_i2c_dev {
|
||||||
|
struct device *dev;
|
||||||
|
struct i2c_adapter adapter;
|
||||||
|
struct completion msg_complete;
|
||||||
|
int irq;
|
||||||
|
bool msg_read;
|
||||||
|
u32 __iomem *base;
|
||||||
|
u32 msg_buf_remaining;
|
||||||
|
u32 msg_len;
|
||||||
|
u32 clk_hz;
|
||||||
|
u32 msg_err;
|
||||||
|
u8 *msg_buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv,
|
||||||
|
unsigned long reg, u32 val)
|
||||||
|
{
|
||||||
|
writel(val, priv->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv,
|
||||||
|
unsigned long reg)
|
||||||
|
{
|
||||||
|
return readl(priv->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
|
||||||
|
{
|
||||||
|
u32 inten;
|
||||||
|
|
||||||
|
inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask;
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
|
||||||
|
{
|
||||||
|
u32 inten;
|
||||||
|
|
||||||
|
inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask;
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv)
|
||||||
|
{
|
||||||
|
u32 thres;
|
||||||
|
|
||||||
|
thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
|
||||||
|
thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
|
||||||
|
{
|
||||||
|
u32 len, i;
|
||||||
|
u8 *buf = priv->msg_buf;
|
||||||
|
|
||||||
|
len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]);
|
||||||
|
priv->msg_buf_remaining -= len;
|
||||||
|
priv->msg_buf += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
|
||||||
|
{
|
||||||
|
u32 len, i;
|
||||||
|
u8 *buf = priv->msg_buf;
|
||||||
|
|
||||||
|
len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
|
||||||
|
XLP9XX_I2C_FIFO_WCNT_MASK;
|
||||||
|
len = min(priv->msg_buf_remaining, len);
|
||||||
|
for (i = 0; i < len; i++, buf++)
|
||||||
|
*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
|
||||||
|
|
||||||
|
priv->msg_buf_remaining -= len;
|
||||||
|
priv->msg_buf = buf;
|
||||||
|
|
||||||
|
if (priv->msg_buf_remaining)
|
||||||
|
xlp9xx_i2c_update_rx_fifo_thres(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct xlp9xx_i2c_dev *priv = dev_id;
|
||||||
|
u32 status;
|
||||||
|
|
||||||
|
status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST);
|
||||||
|
if (status == 0)
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status);
|
||||||
|
if (status & XLP9XX_I2C_STATUS_ERRMASK) {
|
||||||
|
priv->msg_err = status;
|
||||||
|
goto xfer_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SADDR ACK for SMBUS_QUICK */
|
||||||
|
if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0))
|
||||||
|
goto xfer_done;
|
||||||
|
|
||||||
|
if (!priv->msg_read) {
|
||||||
|
if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) {
|
||||||
|
/* TX FIFO got empty, fill it up again */
|
||||||
|
if (priv->msg_buf_remaining)
|
||||||
|
xlp9xx_i2c_fill_tx_fifo(priv);
|
||||||
|
else
|
||||||
|
xlp9xx_i2c_mask_irq(priv,
|
||||||
|
XLP9XX_I2C_INTEN_MFIFOEMTY);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (status & (XLP9XX_I2C_INTEN_DATADONE |
|
||||||
|
XLP9XX_I2C_INTEN_MFIFOHI)) {
|
||||||
|
/* data is in FIFO, read it */
|
||||||
|
if (priv->msg_buf_remaining)
|
||||||
|
xlp9xx_i2c_drain_rx_fifo(priv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer complete */
|
||||||
|
if (status & XLP9XX_I2C_INTEN_DATADONE)
|
||||||
|
goto xfer_done;
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
|
||||||
|
xfer_done:
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
|
||||||
|
complete(&priv->msg_complete);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv)
|
||||||
|
{
|
||||||
|
u32 prescale;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The controller uses 5 * SCL clock internally.
|
||||||
|
* So prescale value should be divided by 5.
|
||||||
|
*/
|
||||||
|
prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz);
|
||||||
|
prescale = ((prescale - 8) / 5) - 1;
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST);
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN |
|
||||||
|
XLP9XX_I2C_CTRL_MASTER);
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale);
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
|
||||||
|
int last_msg)
|
||||||
|
{
|
||||||
|
unsigned long timeleft;
|
||||||
|
u32 intr_mask, cmd, val;
|
||||||
|
|
||||||
|
priv->msg_buf = msg->buf;
|
||||||
|
priv->msg_buf_remaining = priv->msg_len = msg->len;
|
||||||
|
priv->msg_err = 0;
|
||||||
|
priv->msg_read = (msg->flags & I2C_M_RD);
|
||||||
|
reinit_completion(&priv->msg_complete);
|
||||||
|
|
||||||
|
/* Reset FIFO */
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
|
||||||
|
XLP9XX_I2C_MFIFOCTRL_RST);
|
||||||
|
|
||||||
|
/* set FIFO threshold if reading */
|
||||||
|
if (priv->msg_read)
|
||||||
|
xlp9xx_i2c_update_rx_fifo_thres(priv);
|
||||||
|
|
||||||
|
/* set slave addr */
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR,
|
||||||
|
(msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) |
|
||||||
|
(priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0));
|
||||||
|
|
||||||
|
/* Build control word for transfer */
|
||||||
|
val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
|
||||||
|
if (!priv->msg_read)
|
||||||
|
val &= ~XLP9XX_I2C_CTRL_FIFORD;
|
||||||
|
else
|
||||||
|
val |= XLP9XX_I2C_CTRL_FIFORD; /* read */
|
||||||
|
|
||||||
|
if (msg->flags & I2C_M_TEN)
|
||||||
|
val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/
|
||||||
|
else
|
||||||
|
val &= ~XLP9XX_I2C_CTRL_ADDMODE;
|
||||||
|
|
||||||
|
/* set data length to be transferred */
|
||||||
|
val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
|
||||||
|
(msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
|
||||||
|
|
||||||
|
/* fill fifo during tx */
|
||||||
|
if (!priv->msg_read)
|
||||||
|
xlp9xx_i2c_fill_tx_fifo(priv);
|
||||||
|
|
||||||
|
/* set interrupt mask */
|
||||||
|
intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR |
|
||||||
|
XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE);
|
||||||
|
|
||||||
|
if (priv->msg_read) {
|
||||||
|
intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI;
|
||||||
|
if (msg->len == 0)
|
||||||
|
intr_mask |= XLP9XX_I2C_INTEN_SADDR;
|
||||||
|
} else {
|
||||||
|
if (msg->len == 0)
|
||||||
|
intr_mask |= XLP9XX_I2C_INTEN_SADDR;
|
||||||
|
else
|
||||||
|
intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY;
|
||||||
|
}
|
||||||
|
xlp9xx_i2c_unmask_irq(priv, intr_mask);
|
||||||
|
|
||||||
|
/* set cmd reg */
|
||||||
|
cmd = XLP9XX_I2C_CMD_START;
|
||||||
|
cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE);
|
||||||
|
if (last_msg)
|
||||||
|
cmd |= XLP9XX_I2C_CMD_STOP;
|
||||||
|
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd);
|
||||||
|
|
||||||
|
timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS);
|
||||||
|
timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft);
|
||||||
|
|
||||||
|
if (priv->msg_err) {
|
||||||
|
dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err);
|
||||||
|
if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR)
|
||||||
|
xlp9xx_i2c_init(priv);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeleft == 0) {
|
||||||
|
dev_dbg(priv->dev, "i2c transfer timed out!\n");
|
||||||
|
xlp9xx_i2c_init(priv);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||||
|
int num)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
|
||||||
|
{
|
||||||
|
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C |
|
||||||
|
I2C_FUNC_10BIT_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct i2c_algorithm xlp9xx_i2c_algo = {
|
||||||
|
.master_xfer = xlp9xx_i2c_xfer,
|
||||||
|
.functionality = xlp9xx_i2c_functionality,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
|
||||||
|
struct xlp9xx_i2c_dev *priv)
|
||||||
|
{
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
u32 freq;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = of_property_read_u32(np, "clock-frequency", &freq);
|
||||||
|
if (err) {
|
||||||
|
freq = XLP9XX_I2C_DEFAULT_FREQ;
|
||||||
|
dev_dbg(&pdev->dev, "using default frequency %u\n", freq);
|
||||||
|
} else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) {
|
||||||
|
dev_warn(&pdev->dev, "invalid frequency %u, using default\n",
|
||||||
|
freq);
|
||||||
|
freq = XLP9XX_I2C_DEFAULT_FREQ;
|
||||||
|
}
|
||||||
|
priv->clk_hz = freq;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xlp9xx_i2c_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct xlp9xx_i2c_dev *priv;
|
||||||
|
struct resource *res;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
priv->base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(priv->base))
|
||||||
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
priv->irq = platform_get_irq(pdev, 0);
|
||||||
|
if (priv->irq <= 0) {
|
||||||
|
dev_err(&pdev->dev, "invalid irq!\n");
|
||||||
|
return priv->irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
xlp9xx_i2c_get_frequency(pdev, priv);
|
||||||
|
xlp9xx_i2c_init(priv);
|
||||||
|
|
||||||
|
err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0,
|
||||||
|
pdev->name, priv);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "IRQ request failed!\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_completion(&priv->msg_complete);
|
||||||
|
priv->adapter.dev.parent = &pdev->dev;
|
||||||
|
priv->adapter.algo = &xlp9xx_i2c_algo;
|
||||||
|
priv->adapter.dev.of_node = pdev->dev.of_node;
|
||||||
|
priv->dev = &pdev->dev;
|
||||||
|
|
||||||
|
snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c");
|
||||||
|
i2c_set_adapdata(&priv->adapter, priv);
|
||||||
|
|
||||||
|
err = i2c_add_adapter(&priv->adapter);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "failed to add I2C adapter!\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xlp9xx_i2c_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct xlp9xx_i2c_dev *priv;
|
||||||
|
|
||||||
|
priv = platform_get_drvdata(pdev);
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
|
||||||
|
synchronize_irq(priv->irq);
|
||||||
|
i2c_del_adapter(&priv->adapter);
|
||||||
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id xlp9xx_i2c_of_match[] = {
|
||||||
|
{ .compatible = "netlogic,xlp980-i2c", },
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver xlp9xx_i2c_driver = {
|
||||||
|
.probe = xlp9xx_i2c_probe,
|
||||||
|
.remove = xlp9xx_i2c_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "xlp9xx-i2c",
|
||||||
|
.of_match_table = xlp9xx_i2c_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(xlp9xx_i2c_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>");
|
||||||
|
MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -561,7 +561,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
|
||||||
int i = 0, val = 1, ret = 0;
|
int i = 0, val = 1, ret = 0;
|
||||||
|
|
||||||
if (bri->prepare_recovery)
|
if (bri->prepare_recovery)
|
||||||
bri->prepare_recovery(bri);
|
bri->prepare_recovery(adap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By this time SCL is high, as we need to give 9 falling-rising edges
|
* By this time SCL is high, as we need to give 9 falling-rising edges
|
||||||
|
@ -586,7 +586,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bri->unprepare_recovery)
|
if (bri->unprepare_recovery)
|
||||||
bri->unprepare_recovery(bri);
|
bri->unprepare_recovery(adap);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1875,6 +1875,13 @@ static int __init i2c_init(void)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
retval = of_alias_get_highest_id("i2c");
|
||||||
|
|
||||||
|
down_write(&__i2c_board_lock);
|
||||||
|
if (retval >= __i2c_first_dynamic_bus_num)
|
||||||
|
__i2c_first_dynamic_bus_num = retval + 1;
|
||||||
|
up_write(&__i2c_board_lock);
|
||||||
|
|
||||||
retval = bus_register(&i2c_bus_type);
|
retval = bus_register(&i2c_bus_type);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -1926,6 +1933,65 @@ module_exit(i2c_exit);
|
||||||
* ----------------------------------------------------
|
* ----------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Check if val is exceeding the quirk IFF quirk is non 0 */
|
||||||
|
#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))
|
||||||
|
|
||||||
|
static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg)
|
||||||
|
{
|
||||||
|
dev_err_ratelimited(&adap->dev, "adapter quirk: %s (addr 0x%04x, size %u, %s)\n",
|
||||||
|
err_msg, msg->addr, msg->len,
|
||||||
|
msg->flags & I2C_M_RD ? "read" : "write");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||||
|
{
|
||||||
|
const struct i2c_adapter_quirks *q = adap->quirks;
|
||||||
|
int max_num = q->max_num_msgs, i;
|
||||||
|
bool do_len_check = true;
|
||||||
|
|
||||||
|
if (q->flags & I2C_AQ_COMB) {
|
||||||
|
max_num = 2;
|
||||||
|
|
||||||
|
/* special checks for combined messages */
|
||||||
|
if (num == 2) {
|
||||||
|
if (q->flags & I2C_AQ_COMB_WRITE_FIRST && msgs[0].flags & I2C_M_RD)
|
||||||
|
return i2c_quirk_error(adap, &msgs[0], "1st comb msg must be write");
|
||||||
|
|
||||||
|
if (q->flags & I2C_AQ_COMB_READ_SECOND && !(msgs[1].flags & I2C_M_RD))
|
||||||
|
return i2c_quirk_error(adap, &msgs[1], "2nd comb msg must be read");
|
||||||
|
|
||||||
|
if (q->flags & I2C_AQ_COMB_SAME_ADDR && msgs[0].addr != msgs[1].addr)
|
||||||
|
return i2c_quirk_error(adap, &msgs[0], "comb msg only to same addr");
|
||||||
|
|
||||||
|
if (i2c_quirk_exceeded(msgs[0].len, q->max_comb_1st_msg_len))
|
||||||
|
return i2c_quirk_error(adap, &msgs[0], "msg too long");
|
||||||
|
|
||||||
|
if (i2c_quirk_exceeded(msgs[1].len, q->max_comb_2nd_msg_len))
|
||||||
|
return i2c_quirk_error(adap, &msgs[1], "msg too long");
|
||||||
|
|
||||||
|
do_len_check = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2c_quirk_exceeded(num, max_num))
|
||||||
|
return i2c_quirk_error(adap, &msgs[0], "too many messages");
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
u16 len = msgs[i].len;
|
||||||
|
|
||||||
|
if (msgs[i].flags & I2C_M_RD) {
|
||||||
|
if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len))
|
||||||
|
return i2c_quirk_error(adap, &msgs[i], "msg too long");
|
||||||
|
} else {
|
||||||
|
if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len))
|
||||||
|
return i2c_quirk_error(adap, &msgs[i], "msg too long");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __i2c_transfer - unlocked flavor of i2c_transfer
|
* __i2c_transfer - unlocked flavor of i2c_transfer
|
||||||
* @adap: Handle to I2C bus
|
* @adap: Handle to I2C bus
|
||||||
|
@ -1943,6 +2009,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||||
unsigned long orig_jiffies;
|
unsigned long orig_jiffies;
|
||||||
int ret, try;
|
int ret, try;
|
||||||
|
|
||||||
|
if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
/* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
|
/* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
|
||||||
* enabled. This is an efficient way of keeping the for-loop from
|
* enabled. This is an efficient way of keeping the for-loop from
|
||||||
* being executed when not needed.
|
* being executed when not needed.
|
||||||
|
|
|
@ -36,7 +36,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
||||||
struct eeprom_data *eeprom = i2c_get_clientdata(client);
|
struct eeprom_data *eeprom = i2c_get_clientdata(client);
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case I2C_SLAVE_REQ_WRITE_END:
|
case I2C_SLAVE_WRITE_RECEIVED:
|
||||||
if (eeprom->first_write) {
|
if (eeprom->first_write) {
|
||||||
eeprom->buffer_idx = *val;
|
eeprom->buffer_idx = *val;
|
||||||
eeprom->first_write = false;
|
eeprom->first_write = false;
|
||||||
|
@ -47,17 +47,23 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case I2C_SLAVE_REQ_READ_START:
|
case I2C_SLAVE_READ_PROCESSED:
|
||||||
|
/* The previous byte made it to the bus, get next one */
|
||||||
|
eeprom->buffer_idx++;
|
||||||
|
/* fallthrough */
|
||||||
|
case I2C_SLAVE_READ_REQUESTED:
|
||||||
spin_lock(&eeprom->buffer_lock);
|
spin_lock(&eeprom->buffer_lock);
|
||||||
*val = eeprom->buffer[eeprom->buffer_idx];
|
*val = eeprom->buffer[eeprom->buffer_idx];
|
||||||
spin_unlock(&eeprom->buffer_lock);
|
spin_unlock(&eeprom->buffer_lock);
|
||||||
break;
|
/*
|
||||||
|
* Do not increment buffer_idx here, because we don't know if
|
||||||
case I2C_SLAVE_REQ_READ_END:
|
* this byte will be actually used. Read Linux I2C slave docs
|
||||||
eeprom->buffer_idx++;
|
* for details.
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case I2C_SLAVE_STOP:
|
case I2C_SLAVE_STOP:
|
||||||
|
case I2C_SLAVE_WRITE_REQUESTED:
|
||||||
eeprom->first_write = true;
|
eeprom->first_write = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -76,10 +76,9 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
adapter = of_find_i2c_adapter_by_node(adapter_np);
|
adapter = of_find_i2c_adapter_by_node(adapter_np);
|
||||||
if (!adapter) {
|
if (!adapter)
|
||||||
dev_err(&pdev->dev, "Cannot find parent bus\n");
|
|
||||||
return -EPROBE_DEFER;
|
return -EPROBE_DEFER;
|
||||||
}
|
|
||||||
mux->data.parent = i2c_adapter_id(adapter);
|
mux->data.parent = i2c_adapter_id(adapter);
|
||||||
put_device(&adapter->dev);
|
put_device(&adapter->dev);
|
||||||
|
|
||||||
|
@ -177,11 +176,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
parent = i2c_get_adapter(mux->data.parent);
|
parent = i2c_get_adapter(mux->data.parent);
|
||||||
if (!parent) {
|
if (!parent)
|
||||||
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
|
|
||||||
mux->data.parent);
|
|
||||||
return -EPROBE_DEFER;
|
return -EPROBE_DEFER;
|
||||||
}
|
|
||||||
|
|
||||||
mux->parent = parent;
|
mux->parent = parent;
|
||||||
mux->gpio_base = gpio_base;
|
mux->gpio_base = gpio_base;
|
||||||
|
|
|
@ -204,9 +204,9 @@ static int pca954x_probe(struct i2c_client *client,
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
|
|
||||||
/* Get the mux out of reset if a reset GPIO is specified. */
|
/* Get the mux out of reset if a reset GPIO is specified. */
|
||||||
gpio = devm_gpiod_get(&client->dev, "reset");
|
gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
|
||||||
if (!IS_ERR(gpio))
|
if (IS_ERR(gpio))
|
||||||
gpiod_direction_output(gpio, 0);
|
return PTR_ERR(gpio);
|
||||||
|
|
||||||
/* Write the mux register at addr to verify
|
/* Write the mux register at addr to verify
|
||||||
* that the mux is in fact present. This also
|
* that the mux is in fact present. This also
|
||||||
|
|
|
@ -1960,6 +1960,32 @@ int of_alias_get_id(struct device_node *np, const char *stem)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_alias_get_id);
|
EXPORT_SYMBOL_GPL(of_alias_get_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* of_alias_get_highest_id - Get highest alias id for the given stem
|
||||||
|
* @stem: Alias stem to be examined
|
||||||
|
*
|
||||||
|
* The function travels the lookup table to get the highest alias id for the
|
||||||
|
* given alias stem. It returns the alias id if found.
|
||||||
|
*/
|
||||||
|
int of_alias_get_highest_id(const char *stem)
|
||||||
|
{
|
||||||
|
struct alias_prop *app;
|
||||||
|
int id = -ENODEV;
|
||||||
|
|
||||||
|
mutex_lock(&of_mutex);
|
||||||
|
list_for_each_entry(app, &aliases_lookup, link) {
|
||||||
|
if (strcmp(app->stem, stem) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (app->id > id)
|
||||||
|
id = app->id;
|
||||||
|
}
|
||||||
|
mutex_unlock(&of_mutex);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
|
||||||
|
|
||||||
const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
|
const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
|
||||||
u32 *pu)
|
u32 *pu)
|
||||||
{
|
{
|
||||||
|
|
|
@ -253,10 +253,10 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||||
enum i2c_slave_event {
|
enum i2c_slave_event {
|
||||||
I2C_SLAVE_REQ_READ_START,
|
I2C_SLAVE_READ_REQUESTED,
|
||||||
I2C_SLAVE_REQ_READ_END,
|
I2C_SLAVE_WRITE_REQUESTED,
|
||||||
I2C_SLAVE_REQ_WRITE_START,
|
I2C_SLAVE_READ_PROCESSED,
|
||||||
I2C_SLAVE_REQ_WRITE_END,
|
I2C_SLAVE_WRITE_RECEIVED,
|
||||||
I2C_SLAVE_STOP,
|
I2C_SLAVE_STOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -435,8 +435,8 @@ struct i2c_bus_recovery_info {
|
||||||
void (*set_scl)(struct i2c_adapter *, int val);
|
void (*set_scl)(struct i2c_adapter *, int val);
|
||||||
int (*get_sda)(struct i2c_adapter *);
|
int (*get_sda)(struct i2c_adapter *);
|
||||||
|
|
||||||
void (*prepare_recovery)(struct i2c_bus_recovery_info *bri);
|
void (*prepare_recovery)(struct i2c_adapter *);
|
||||||
void (*unprepare_recovery)(struct i2c_bus_recovery_info *bri);
|
void (*unprepare_recovery)(struct i2c_adapter *);
|
||||||
|
|
||||||
/* gpio recovery */
|
/* gpio recovery */
|
||||||
int scl_gpio;
|
int scl_gpio;
|
||||||
|
@ -449,6 +449,48 @@ int i2c_recover_bus(struct i2c_adapter *adap);
|
||||||
int i2c_generic_gpio_recovery(struct i2c_adapter *adap);
|
int i2c_generic_gpio_recovery(struct i2c_adapter *adap);
|
||||||
int i2c_generic_scl_recovery(struct i2c_adapter *adap);
|
int i2c_generic_scl_recovery(struct i2c_adapter *adap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct i2c_adapter_quirks - describe flaws of an i2c adapter
|
||||||
|
* @flags: see I2C_AQ_* for possible flags and read below
|
||||||
|
* @max_num_msgs: maximum number of messages per transfer
|
||||||
|
* @max_write_len: maximum length of a write message
|
||||||
|
* @max_read_len: maximum length of a read message
|
||||||
|
* @max_comb_1st_msg_len: maximum length of the first msg in a combined message
|
||||||
|
* @max_comb_2nd_msg_len: maximum length of the second msg in a combined message
|
||||||
|
*
|
||||||
|
* Note about combined messages: Some I2C controllers can only send one message
|
||||||
|
* per transfer, plus something called combined message or write-then-read.
|
||||||
|
* This is (usually) a small write message followed by a read message and
|
||||||
|
* barely enough to access register based devices like EEPROMs. There is a flag
|
||||||
|
* to support this mode. It implies max_num_msg = 2 and does the length checks
|
||||||
|
* with max_comb_*_len because combined message mode usually has its own
|
||||||
|
* limitations. Because of HW implementations, some controllers can actually do
|
||||||
|
* write-then-anything or other variants. To support that, write-then-read has
|
||||||
|
* been broken out into smaller bits like write-first and read-second which can
|
||||||
|
* be combined as needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct i2c_adapter_quirks {
|
||||||
|
u64 flags;
|
||||||
|
int max_num_msgs;
|
||||||
|
u16 max_write_len;
|
||||||
|
u16 max_read_len;
|
||||||
|
u16 max_comb_1st_msg_len;
|
||||||
|
u16 max_comb_2nd_msg_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* enforce max_num_msgs = 2 and use max_comb_*_len for length checks */
|
||||||
|
#define I2C_AQ_COMB BIT(0)
|
||||||
|
/* first combined message must be write */
|
||||||
|
#define I2C_AQ_COMB_WRITE_FIRST BIT(1)
|
||||||
|
/* second combined message must be read */
|
||||||
|
#define I2C_AQ_COMB_READ_SECOND BIT(2)
|
||||||
|
/* both combined messages must have the same target address */
|
||||||
|
#define I2C_AQ_COMB_SAME_ADDR BIT(3)
|
||||||
|
/* convenience macro for typical write-then read case */
|
||||||
|
#define I2C_AQ_COMB_WRITE_THEN_READ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \
|
||||||
|
I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* i2c_adapter is the structure used to identify a physical i2c bus along
|
* i2c_adapter is the structure used to identify a physical i2c bus along
|
||||||
* with the access algorithms necessary to access it.
|
* with the access algorithms necessary to access it.
|
||||||
|
@ -474,6 +516,7 @@ struct i2c_adapter {
|
||||||
struct list_head userspace_clients;
|
struct list_head userspace_clients;
|
||||||
|
|
||||||
struct i2c_bus_recovery_info *bus_recovery_info;
|
struct i2c_bus_recovery_info *bus_recovery_info;
|
||||||
|
const struct i2c_adapter_quirks *quirks;
|
||||||
};
|
};
|
||||||
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
|
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
|
||||||
|
|
||||||
|
|
|
@ -332,6 +332,7 @@ extern int of_count_phandle_with_args(const struct device_node *np,
|
||||||
|
|
||||||
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
|
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
|
||||||
extern int of_alias_get_id(struct device_node *np, const char *stem);
|
extern int of_alias_get_id(struct device_node *np, const char *stem);
|
||||||
|
extern int of_alias_get_highest_id(const char *stem);
|
||||||
|
|
||||||
extern int of_machine_is_compatible(const char *compat);
|
extern int of_machine_is_compatible(const char *compat);
|
||||||
|
|
||||||
|
@ -594,6 +595,11 @@ static inline int of_alias_get_id(struct device_node *np, const char *stem)
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int of_alias_get_highest_id(const char *stem)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int of_machine_is_compatible(const char *compat)
|
static inline int of_machine_is_compatible(const char *compat)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct davinci_i2c_platform_data {
|
||||||
unsigned int bus_delay; /* post-transaction delay (usec) */
|
unsigned int bus_delay; /* post-transaction delay (usec) */
|
||||||
unsigned int sda_pin; /* GPIO pin ID to use for SDA */
|
unsigned int sda_pin; /* GPIO pin ID to use for SDA */
|
||||||
unsigned int scl_pin; /* GPIO pin ID to use for SCL */
|
unsigned int scl_pin; /* GPIO pin ID to use for SCL */
|
||||||
|
bool has_pfunc; /*chip has a ICPFUNC register */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* for board setup code */
|
/* for board setup code */
|
||||||
|
|
Loading…
Reference in New Issue