mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
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:
@@ -10,6 +10,9 @@ Required properties:
|
||||
Recommended properties :
|
||||
- interrupts : standard interrupt property.
|
||||
- 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):
|
||||
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
|
||||
neonode Neonode Inc.
|
||||
netgear NETGEAR
|
||||
netlogic Broadcom Corporation (formerly NetLogic Microsystems)
|
||||
newhaven Newhaven Display International
|
||||
nintendo Nintendo
|
||||
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
|
||||
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
|
||||
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
|
||||
tristate "EFM32 I2C controller"
|
||||
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
|
||||
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
|
||||
tristate "Kontron COM I2C Controller"
|
||||
depends on MFD_KEMPLD
|
||||
@@ -898,6 +916,16 @@ config I2C_XLR
|
||||
This driver can also be built as a module. If so, the module
|
||||
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
|
||||
tristate "Renesas R-Car I2C Controller"
|
||||
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
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.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_EG20T) += i2c-eg20t.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_IMX) += i2c-imx.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_MESON) += i2c-meson.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_XILINX) += i2c-xiic.o
|
||||
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
|
||||
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
|
||||
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
|
||||
|
||||
# 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)
|
||||
{
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
bool has_unre_flag = dev->pdata->has_unre_flag;
|
||||
|
||||
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,
|
||||
dev->adapter.timeout);
|
||||
if (ret == 0) {
|
||||
time_left = wait_for_completion_timeout(&dev->cmd_complete,
|
||||
dev->adapter.timeout);
|
||||
if (time_left == 0) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
at91_init_twi_bus(dev);
|
||||
ret = -ETIMEDOUT;
|
||||
@@ -487,30 +488,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
if (num == 2) {
|
||||
int internal_address = 0;
|
||||
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 */
|
||||
m_start = &msg[1];
|
||||
for (i = 0; i < msg->len; ++i) {
|
||||
@@ -540,6 +521,15 @@ out:
|
||||
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)
|
||||
{
|
||||
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.class = I2C_CLASS_DEPRECATED;
|
||||
dev->adapter.algo = &at91_twi_algorithm;
|
||||
dev->adapter.quirks = &at91_twi_quirks;
|
||||
dev->adapter.dev.parent = dev->dev;
|
||||
dev->adapter.nr = pdev->id;
|
||||
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 rx_xfer, tx_xfer;
|
||||
u32 addr_1, addr_2;
|
||||
int ret;
|
||||
|
||||
if (msg->len > 255) {
|
||||
dev_warn(idev->dev, "unsupported length %u\n", msg->len);
|
||||
return -EINVAL;
|
||||
}
|
||||
unsigned long time_left;
|
||||
|
||||
idev->msg = msg;
|
||||
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);
|
||||
|
||||
ret = wait_for_completion_timeout(&idev->msg_complete,
|
||||
I2C_XFER_TIMEOUT);
|
||||
time_left = wait_for_completion_timeout(&idev->msg_complete,
|
||||
I2C_XFER_TIMEOUT);
|
||||
|
||||
i2c_int_disable(idev, int_mask);
|
||||
|
||||
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
|
||||
dev_warn(idev->dev, "busy after xfer\n");
|
||||
|
||||
if (ret == 0)
|
||||
if (time_left == 0)
|
||||
idev->msg_err = -ETIMEDOUT;
|
||||
|
||||
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)
|
||||
{
|
||||
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
|
||||
reinit_completion(&idev->msg_complete);
|
||||
|
||||
/* Issue stop */
|
||||
writel(0xb, idev->base + MST_COMMAND);
|
||||
i2c_int_enable(idev, int_mask);
|
||||
ret = wait_for_completion_timeout(&idev->msg_complete,
|
||||
I2C_STOP_TIMEOUT);
|
||||
time_left = wait_for_completion_timeout(&idev->msg_complete,
|
||||
I2C_STOP_TIMEOUT);
|
||||
i2c_int_disable(idev, int_mask);
|
||||
if (ret == 0)
|
||||
if (time_left == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
|
||||
@@ -454,6 +449,11 @@ static const struct i2c_algorithm axxia_i2c_algo = {
|
||||
.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)
|
||||
{
|
||||
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));
|
||||
idev->adapter.owner = THIS_MODULE;
|
||||
idev->adapter.algo = &axxia_i2c_algo;
|
||||
idev->adapter.quirks = &axxia_i2c_quirks;
|
||||
idev->adapter.dev.parent = &pdev->dev;
|
||||
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;
|
||||
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 */
|
||||
if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
|
||||
BIT(M_CMD_START_BUSY_SHIFT))) {
|
||||
@@ -287,6 +279,12 @@ static const struct i2c_algorithm bcm_iproc_algo = {
|
||||
.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)
|
||||
{
|
||||
unsigned int bus_speed;
|
||||
@@ -413,6 +411,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
|
||||
i2c_set_adapdata(adap, iproc_i2c);
|
||||
strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &bcm_iproc_algo;
|
||||
adap->quirks = &bcm_iproc_i2c_quirks;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
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)
|
||||
{
|
||||
u32 c;
|
||||
int time_left;
|
||||
unsigned long time_left;
|
||||
|
||||
i2c_dev->msg_buf = msg->buf;
|
||||
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,
|
||||
struct i2c_adapter *adap)
|
||||
{
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
u32 reg;
|
||||
|
||||
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);
|
||||
|
||||
/* Wait for the signal of completion */
|
||||
ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
|
||||
if (!ret) {
|
||||
time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
|
||||
if (time_left == 0) {
|
||||
cdns_i2c_master_reset(adap);
|
||||
dev_err(id->adap.dev.parent,
|
||||
"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_ram __iomem *i2c_ram = cpm->i2c_ram;
|
||||
struct i2c_msg *pmsg;
|
||||
int ret, i;
|
||||
int ret;
|
||||
int tptr;
|
||||
int rptr;
|
||||
cbd_t __iomem *tbdf;
|
||||
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 */
|
||||
out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
|
||||
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,
|
||||
};
|
||||
|
||||
/* 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 = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-cpm",
|
||||
.algo = &cpm_i2c_algo,
|
||||
.quirks = &cpm_i2c_quirks,
|
||||
};
|
||||
|
||||
static int cpm_i2c_setup(struct cpm_i2c *cpm)
|
||||
|
||||
@@ -60,6 +60,12 @@
|
||||
#define DAVINCI_I2C_IVR_REG 0x28
|
||||
#define DAVINCI_I2C_EMDR_REG 0x2c
|
||||
#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_SCD 0x06
|
||||
@@ -93,6 +99,29 @@
|
||||
#define DAVINCI_I2C_IMR_NACK BIT(1)
|
||||
#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 device *dev;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
int val)
|
||||
{
|
||||
@@ -262,6 +254,99 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
|
||||
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
|
||||
*/
|
||||
@@ -282,8 +367,7 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
|
||||
return -ETIMEDOUT;
|
||||
} else {
|
||||
to_cnt = 0;
|
||||
davinci_i2c_recover_bus(dev);
|
||||
i2c_davinci_init(dev);
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
}
|
||||
}
|
||||
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;
|
||||
u32 flag;
|
||||
u16 w;
|
||||
int r;
|
||||
unsigned long time_left;
|
||||
|
||||
/* Introduce a delay, required for some boards (e.g Davinci EVM) */
|
||||
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;
|
||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
|
||||
|
||||
r = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout);
|
||||
if (r == 0) {
|
||||
time_left = wait_for_completion_timeout(&dev->cmd_complete,
|
||||
dev->adapter.timeout);
|
||||
if (!time_left) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
davinci_i2c_recover_bus(dev);
|
||||
i2c_davinci_init(dev);
|
||||
i2c_recover_bus(adap);
|
||||
dev->buf_len = 0;
|
||||
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
|
||||
* or dev->cmd_err denotes an error.
|
||||
*/
|
||||
if (r >= 0) {
|
||||
dev_err(dev->dev, "abnormal termination buf_len=%i\n",
|
||||
dev->buf_len);
|
||||
r = -EREMOTEIO;
|
||||
}
|
||||
dev_err(dev->dev, "abnormal termination buf_len=%i\n",
|
||||
dev->buf_len);
|
||||
dev->terminate = 1;
|
||||
wmb();
|
||||
dev->buf_len = 0;
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* no error */
|
||||
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",
|
||||
&prop))
|
||||
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) {
|
||||
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->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;
|
||||
r = i2c_add_numbered_adapter(adap);
|
||||
if (r) {
|
||||
|
||||
@@ -656,8 +656,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
i2c_dw_xfer_init(dev);
|
||||
|
||||
/* wait for tx to complete */
|
||||
ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
|
||||
if (ret == 0) {
|
||||
if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
/* i2c_dw_init implicitly disables the adapter */
|
||||
i2c_dw_init(dev);
|
||||
|
||||
@@ -143,10 +143,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
|
||||
u32 clk_freq, ht = 0;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource?\n");
|
||||
return irq; /* -ENXIO */
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
|
||||
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");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user