mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
Merge branch 'i2c/for-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "Features: - new drivers: Renesas EMEV2, register based MUX, NXP LPC2xxx - core: scans DT and assigns wakeup interrupts. no driver changes needed. - core: some refcouting issues fixed and better API for that - core: new helper function for best effort block read emulation - slave framework: proper DT bindings and userspace instantiation - some bigger work for xiic, pxa, omap drivers .. and quite a number of smaller driver fixes, cleanups, improvements" * 'i2c/for-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (65 commits) i2c: mux: reg Change ioread endianness for readback i2c: mux: reg: fix compilation warnings i2c: mux: reg: simplify register size checking i2c: muxes: fix leaked i2c adapter device node references i2c: allow specifying separate wakeup interrupt in device tree of/irq: export of_get_irq_byname() i2c: xgene-slimpro: dma_mapping_error() doesn't return an error code i2c: Replace I2C_CROS_EC_TUNNEL dependency eeprom: at24: use i2c_smbus_read_i2c_block_data_or_emulated i2c: core: Add support for best effort block read emulation i2c: lpc2k: add driver i2c: mux: Add register-based mux i2c-mux-reg i2c: dt: describe generic bindings i2c: slave: print warning if slave flag not set i2c: support 10 bit and slave addresses in sysfs 'new_device' i2c: take address space into account when checking for used addresses i2c: apply DT flags when probing i2c: make address check indpendent from client struct i2c: rename address check functions i2c: apply address offset for slaves, too ...
This commit is contained in:
@@ -2,7 +2,11 @@ Binding for the Cadence I2C controller
|
||||
|
||||
Required properties:
|
||||
- reg: Physical base address and size of the controller's register area.
|
||||
- compatible: Compatibility string. Must be 'cdns,i2c-r1p10'.
|
||||
- compatible: Should contain one of:
|
||||
* "cdns,i2c-r1p10"
|
||||
Note: Use this when cadence i2c controller version 1.0 is used.
|
||||
* "cdns,i2c-r1p14"
|
||||
Note: Use this when cadence i2c controller version 1.4 is used.
|
||||
- clocks: Input clock specifier. Refer to common clock bindings.
|
||||
- interrupts: Interrupt specifier. Refer to interrupt bindings.
|
||||
- #address-cells: Should be 1.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
Device tree configuration for Renesas EMEV2 IIC controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,iic-emev2"
|
||||
- reg : address start and address range size of device
|
||||
- interrupts : specifier for the IIC controller interrupt
|
||||
- clocks : phandle to the IP core SCLK
|
||||
- clock-names : must be "sclk"
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
|
||||
Example:
|
||||
|
||||
iic0: i2c@e0070000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "renesas,iic-emev2";
|
||||
reg = <0xe0070000 0x28>;
|
||||
interrupts = <0 32 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&iic0_sclk>;
|
||||
clock-names = "sclk";
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
NXP I2C controller for LPC2xxx/178x/18xx/43xx
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "nxp,lpc1788-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:
|
||||
i2c0: i2c@400a1000 {
|
||||
compatible = "nxp,lpc1788-i2c";
|
||||
reg = <0x400a1000 0x1000>;
|
||||
interrupts = <18>;
|
||||
clocks = <&ccu1 CLK_APB1_I2C0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
clock-frequency = <400000>;
|
||||
|
||||
lm75@48 {
|
||||
compatible = "nxp,lm75";
|
||||
reg = <0x48>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
Register-based I2C Bus Mux
|
||||
|
||||
This binding describes an I2C bus multiplexer that uses a single register
|
||||
to route the I2C signals.
|
||||
|
||||
Required properties:
|
||||
- compatible: i2c-mux-reg
|
||||
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
|
||||
port is connected to.
|
||||
* Standard I2C mux properties. See mux.txt in this directory.
|
||||
* I2C child bus nodes. See mux.txt in this directory.
|
||||
|
||||
Optional properties:
|
||||
- reg: this pair of <offset size> specifies the register to control the mux.
|
||||
The <offset size> depends on its parent node. It can be any memory-mapped
|
||||
address. The size must be either 1, 2, or 4 bytes. If reg is omitted, the
|
||||
resource of this device will be used.
|
||||
- little-endian: The existence indicates the register is in little endian.
|
||||
- big-endian: The existence indicates the register is in big endian.
|
||||
If both little-endian and big-endian are omitted, the endianness of the
|
||||
CPU will be used.
|
||||
- write-only: The existence indicates the register is write-only.
|
||||
- idle-state: value to set the muxer to when idle. When no value is
|
||||
given, it defaults to the last value used.
|
||||
|
||||
Whenever an access is made to a device on a child bus, the value set
|
||||
in the revelant node's reg property will be output to the register.
|
||||
|
||||
If an idle state is defined, using the idle-state (optional) property,
|
||||
whenever an access is not being made to a device on a child bus, the
|
||||
register will be set according to the idle value.
|
||||
|
||||
If an idle state is not defined, the most recently used value will be
|
||||
left programmed into the register.
|
||||
|
||||
Example of a mux on PCIe card, the host is a powerpc SoC (big endian):
|
||||
|
||||
i2c-mux {
|
||||
/* the <offset size> depends on the address translation
|
||||
* of the parent device. If omitted, device resource
|
||||
* will be used instead. The size is to determine
|
||||
* whether iowrite32, iowrite16, or iowrite8 will be used.
|
||||
*/
|
||||
reg = <0x6028 0x4>;
|
||||
little-endian; /* little endian register on PCIe */
|
||||
compatible = "i2c-mux-reg";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
i2c-parent = <&i2c1>;
|
||||
i2c@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
si5338: clock-generator@70 {
|
||||
compatible = "silabs,si5338";
|
||||
reg = <0x70>;
|
||||
/* other stuff */
|
||||
};
|
||||
};
|
||||
|
||||
i2c@1 {
|
||||
/* data is written using iowrite32 */
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
si5338: clock-generator@70 {
|
||||
compatible = "silabs,si5338";
|
||||
reg = <0x70>;
|
||||
/* other stuff */
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
Generic device tree bindings for I2C busses
|
||||
===========================================
|
||||
|
||||
This document describes generic bindings which can be used to describe I2C
|
||||
busses in a device tree.
|
||||
|
||||
Required properties
|
||||
-------------------
|
||||
|
||||
- #address-cells - should be <1>. Read more about addresses below.
|
||||
- #size-cells - should be <0>.
|
||||
- compatible - name of I2C bus controller following generic names
|
||||
recommended practice.
|
||||
|
||||
For other required properties e.g. to describe register sets,
|
||||
clocks, etc. check the binding documentation of the specific driver.
|
||||
|
||||
The cells properties above define that an address of children of an I2C bus
|
||||
are described by a single value. This is usually a 7 bit address. However,
|
||||
flags can be attached to the address. I2C_TEN_BIT_ADDRESS is used to mark a 10
|
||||
bit address. It is needed to avoid the ambiguity between e.g. a 7 bit address
|
||||
of 0x50 and a 10 bit address of 0x050 which, in theory, can be on the same bus.
|
||||
Another flag is I2C_OWN_SLAVE_ADDRESS to mark addresses on which we listen to
|
||||
be devices ourselves.
|
||||
|
||||
Optional properties
|
||||
-------------------
|
||||
|
||||
These properties may not be supported by all drivers. However, if a driver
|
||||
wants to support one of the below features, it should adapt the bindings below.
|
||||
|
||||
- clock-frequency - frequency of bus clock in Hz.
|
||||
- wakeup-source - device can be used as a wakeup source.
|
||||
|
||||
- interrupts - interrupts used by the device.
|
||||
- interrupt-names - "irq" and "wakeup" names are recognized by I2C core,
|
||||
other names are left to individual drivers.
|
||||
|
||||
Binding may contain optional "interrupts" property, describing interrupts
|
||||
used by the device. I2C core will assign "irq" interrupt (or the very first
|
||||
interrupt if not using interrupt names) as primary interrupt for the slave.
|
||||
|
||||
Also, if device is marked as a wakeup source, I2C core will set up "wakeup"
|
||||
interrupt for the device. If "wakeup" interrupt name is not present in the
|
||||
binding, then primary interrupt will be used as wakeup interrupt.
|
||||
@@ -95,6 +95,8 @@ stm,m41t00 Serial Access TIMEKEEPER
|
||||
stm,m41t62 Serial real-time clock (RTC) with alarm
|
||||
stm,m41t80 M41T80 - SERIAL ACCESS RTC WITH ALARMS
|
||||
taos,tsl2550 Ambient Light Sensor with SMBUS/Two Wire Serial Interface
|
||||
ti,ads7828 8-Channels, 12-bit ADC
|
||||
ti,ads7830 8-Channels, 8-bit ADC
|
||||
ti,tsc2003 I2C Touch-Screen Controller
|
||||
ti,tmp102 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface
|
||||
ti,tmp103 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface
|
||||
|
||||
@@ -20,6 +20,7 @@ It currently supports the following devices:
|
||||
* (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031
|
||||
* (type=6) Barco LPT->DVI (K5800236) adapter
|
||||
* (type=7) One For All JP1 parallel port adapter
|
||||
* (type=8) VCT-jig
|
||||
|
||||
These devices use different pinout configurations, so you have to tell
|
||||
the driver what you have, using the type module parameter. There is no
|
||||
|
||||
@@ -31,10 +31,13 @@ User manual
|
||||
===========
|
||||
|
||||
I2C slave backends behave like standard I2C clients. So, you can instantiate
|
||||
them as described in the document 'instantiating-devices'. A quick example for
|
||||
instantiating the slave-eeprom driver from userspace at address 0x64 on bus 1:
|
||||
them as described in the document 'instantiating-devices'. The only difference
|
||||
is that i2c slave backends have their own address space. So, you have to add
|
||||
0x1000 to the address you would originally request. An example for
|
||||
instantiating the slave-eeprom driver from userspace at the 7 bit address 0x64
|
||||
on bus 1:
|
||||
|
||||
# echo slave-24c02 0x64 > /sys/bus/i2c/devices/i2c-1/new_device
|
||||
# echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-1/new_device
|
||||
|
||||
Each backend should come with separate documentation to describe its specific
|
||||
behaviour and setup.
|
||||
|
||||
@@ -2,6 +2,10 @@ The I2C protocol knows about two kinds of device addresses: normal 7 bit
|
||||
addresses, and an extended set of 10 bit addresses. The sets of addresses
|
||||
do not intersect: the 7 bit address 0x10 is not the same as the 10 bit
|
||||
address 0x10 (though a single device could respond to both of them).
|
||||
To avoid ambiguity, the user sees 10 bit addresses mapped to a different
|
||||
address space, namely 0xa000-0xa3ff. The leading 0xa (= 10) represents the
|
||||
10 bit mode. This is used for creating device names in sysfs. It is also
|
||||
needed when instantiating 10 bit devices via the new_device file in sysfs.
|
||||
|
||||
I2C messages to and from 10-bit address devices have a different format.
|
||||
See the I2C specification for the details.
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#define USIBU1_RSTCTRL 0x0ac
|
||||
#define USIBU2_RSTCTRL 0x0b0
|
||||
#define USIBU3_RSTCTRL 0x0b4
|
||||
#define IIC0_RSTCTRL 0x0dc
|
||||
#define IIC1_RSTCTRL 0x0e0
|
||||
#define STI_RSTCTRL 0x124
|
||||
#define STI_CLKSEL 0x688
|
||||
|
||||
@@ -66,6 +68,10 @@ static void __init emev2_smu_init(void)
|
||||
emev2_smu_write(2, USIBU1_RSTCTRL);
|
||||
emev2_smu_write(2, USIBU2_RSTCTRL);
|
||||
emev2_smu_write(2, USIBU3_RSTCTRL);
|
||||
|
||||
/* deassert reset for IIC0->IIC1 */
|
||||
emev2_smu_write(1, IIC0_RSTCTRL);
|
||||
emev2_smu_write(1, IIC1_RSTCTRL);
|
||||
}
|
||||
|
||||
static void __init emev2_smu_clkdiv_init(struct device_node *np)
|
||||
|
||||
@@ -526,6 +526,13 @@ config I2C_EG20T
|
||||
ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
|
||||
ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
|
||||
|
||||
config I2C_EMEV2
|
||||
tristate "EMMA Mobile series I2C adapter"
|
||||
depends on HAVE_CLK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Renesas Electronics EM/EV family of processors.
|
||||
|
||||
config I2C_EXYNOS5
|
||||
tristate "Exynos5 high-speed I2C driver"
|
||||
depends on ARCH_EXYNOS && OF
|
||||
@@ -612,6 +619,16 @@ config I2C_KEMPLD
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-kempld.
|
||||
|
||||
config I2C_LPC2K
|
||||
tristate "I2C bus support for NXP LPC2K/LPC178x/18xx/43xx"
|
||||
depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
|
||||
help
|
||||
This driver supports the I2C interface found several NXP
|
||||
devices including LPC2xxx, LPC178x/7x and LPC18xx/43xx.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-lpc2k.
|
||||
|
||||
config I2C_MESON
|
||||
tristate "Amlogic Meson I2C controller"
|
||||
depends on ARCH_MESON
|
||||
@@ -1123,7 +1140,7 @@ config I2C_SIBYTE
|
||||
|
||||
config I2C_CROS_EC_TUNNEL
|
||||
tristate "ChromeOS EC tunnel I2C bus"
|
||||
depends on CROS_EC_PROTO
|
||||
depends on MFD_CROS_EC
|
||||
help
|
||||
If you say yes here you get an I2C bus that will tunnel i2c commands
|
||||
through to the other side of the ChromeOS EC to the i2c bus
|
||||
|
||||
@@ -48,6 +48,7 @@ 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_EMEV2) += i2c-emev2.o
|
||||
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
|
||||
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
|
||||
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
|
||||
@@ -58,6 +59,7 @@ 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_LPC2K) += i2c-lpc2k.o
|
||||
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
|
||||
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
||||
obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/* Register offsets for the I2C device. */
|
||||
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
|
||||
@@ -113,6 +114,8 @@
|
||||
|
||||
#define CDNS_I2C_TIMEOUT_MAX 0xFF
|
||||
|
||||
#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
|
||||
|
||||
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
|
||||
#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
|
||||
|
||||
@@ -135,6 +138,7 @@
|
||||
* @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
|
||||
* @clk: Pointer to struct clk
|
||||
* @clk_rate_change_nb: Notifier block for clock rate changes
|
||||
* @quirks: flag for broken hold bit usage in r1p10
|
||||
*/
|
||||
struct cdns_i2c {
|
||||
void __iomem *membase;
|
||||
@@ -154,6 +158,11 @@ struct cdns_i2c {
|
||||
unsigned int bus_hold_flag;
|
||||
struct clk *clk;
|
||||
struct notifier_block clk_rate_change_nb;
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
struct cdns_platform_data {
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \
|
||||
@@ -172,6 +181,12 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
|
||||
cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
|
||||
}
|
||||
|
||||
static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround)
|
||||
{
|
||||
return (hold_wrkaround &&
|
||||
(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_i2c_isr - Interrupt handler for the I2C device
|
||||
* @irq: irq number for the I2C device
|
||||
@@ -186,6 +201,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
{
|
||||
unsigned int isr_status, avail_bytes, updatetx;
|
||||
unsigned int bytes_to_send;
|
||||
bool hold_quirk;
|
||||
struct cdns_i2c *id = ptr;
|
||||
/* Signal completion only after everything is updated */
|
||||
int done_flag = 0;
|
||||
@@ -208,6 +224,8 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
if (id->recv_count > id->curr_recv_count)
|
||||
updatetx = 1;
|
||||
|
||||
hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
|
||||
|
||||
/* When receiving, handle data interrupt and completion interrupt */
|
||||
if (id->p_recv_buf &&
|
||||
((isr_status & CDNS_I2C_IXR_COMP) ||
|
||||
@@ -229,8 +247,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
id->recv_count--;
|
||||
id->curr_recv_count--;
|
||||
|
||||
if (updatetx &&
|
||||
(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1))
|
||||
if (cdns_is_holdquirk(id, hold_quirk))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -241,8 +258,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
* maintain transfer size non-zero while performing a large
|
||||
* receive operation.
|
||||
*/
|
||||
if (updatetx &&
|
||||
(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) {
|
||||
if (cdns_is_holdquirk(id, hold_quirk)) {
|
||||
/* wait while fifo is full */
|
||||
while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
|
||||
(id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
|
||||
@@ -264,6 +280,22 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
CDNS_I2C_XFER_SIZE_OFFSET);
|
||||
id->curr_recv_count = id->recv_count;
|
||||
}
|
||||
} else if (id->recv_count && !hold_quirk &&
|
||||
!id->curr_recv_count) {
|
||||
|
||||
/* Set the slave address in address register*/
|
||||
cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
|
||||
CDNS_I2C_ADDR_OFFSET);
|
||||
|
||||
if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
|
||||
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
|
||||
CDNS_I2C_XFER_SIZE_OFFSET);
|
||||
id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
|
||||
} else {
|
||||
cdns_i2c_writereg(id->recv_count,
|
||||
CDNS_I2C_XFER_SIZE_OFFSET);
|
||||
id->curr_recv_count = id->recv_count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear hold (if not repeated start) and signal completion */
|
||||
@@ -535,11 +567,13 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int ret, count;
|
||||
u32 reg;
|
||||
struct cdns_i2c *id = adap->algo_data;
|
||||
bool hold_quirk;
|
||||
|
||||
/* Check if the bus is free */
|
||||
if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA)
|
||||
return -EAGAIN;
|
||||
|
||||
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
|
||||
/*
|
||||
* Set the flag to one when multiple messages are to be
|
||||
* processed with a repeated start.
|
||||
@@ -552,7 +586,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
* followed by any other message, an error is returned
|
||||
* indicating that this sequence is not supported.
|
||||
*/
|
||||
for (count = 0; count < num - 1; count++) {
|
||||
for (count = 0; (count < num - 1 && hold_quirk); count++) {
|
||||
if (msgs[count].flags & I2C_M_RD) {
|
||||
dev_warn(adap->dev.parent,
|
||||
"Can't do repeated start after a receive message\n");
|
||||
@@ -815,6 +849,17 @@ static int __maybe_unused cdns_i2c_resume(struct device *_dev)
|
||||
static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend,
|
||||
cdns_i2c_resume);
|
||||
|
||||
static const struct cdns_platform_data r1p10_i2c_def = {
|
||||
.quirks = CDNS_I2C_BROKEN_HOLD_BIT,
|
||||
};
|
||||
|
||||
static const struct of_device_id cdns_i2c_of_match[] = {
|
||||
{ .compatible = "cdns,i2c-r1p10", .data = &r1p10_i2c_def },
|
||||
{ .compatible = "cdns,i2c-r1p14",},
|
||||
{ /* end of table */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
|
||||
|
||||
/**
|
||||
* cdns_i2c_probe - Platform registration call
|
||||
* @pdev: Handle to the platform device structure
|
||||
@@ -830,6 +875,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||
struct resource *r_mem;
|
||||
struct cdns_i2c *id;
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
|
||||
id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
|
||||
if (!id)
|
||||
@@ -837,6 +883,12 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, id);
|
||||
|
||||
match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node);
|
||||
if (match && match->data) {
|
||||
const struct cdns_platform_data *data = match->data;
|
||||
id->quirks = data->quirks;
|
||||
}
|
||||
|
||||
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
|
||||
if (IS_ERR(id->membase))
|
||||
@@ -844,6 +896,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
id->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
id->adap.owner = THIS_MODULE;
|
||||
id->adap.dev.of_node = pdev->dev.of_node;
|
||||
id->adap.algo = &cdns_i2c_algo;
|
||||
id->adap.timeout = CDNS_I2C_TIMEOUT;
|
||||
@@ -935,12 +988,6 @@ static int cdns_i2c_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cdns_i2c_of_match[] = {
|
||||
{ .compatible = "cdns,i2c-r1p10", },
|
||||
{ /* end of table */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
|
||||
|
||||
static struct platform_driver cdns_i2c_drv = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
|
||||
@@ -777,8 +777,7 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
||||
|
||||
enabled = dw_readl(dev, DW_IC_ENABLE);
|
||||
stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
|
||||
dev_dbg(dev->dev, "%s: %s enabled= 0x%x stat=0x%x\n", __func__,
|
||||
dev->adapter.name, enabled, stat);
|
||||
dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled, stat);
|
||||
if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
|
||||
return IRQ_NONE;
|
||||
|
||||
|
||||
@@ -260,8 +260,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
||||
|
||||
snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
|
||||
|
||||
r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
|
||||
adap->name, dev);
|
||||
r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr,
|
||||
IRQF_SHARED | IRQF_COND_SUSPEND, adap->name, dev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
|
||||
return r;
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* I2C driver for the Renesas EMEV2 SoC
|
||||
*
|
||||
* Copyright (C) 2015 Wolfram Sang <wsa@sang-engineering.com>
|
||||
* Copyright 2013 Codethink Ltd.
|
||||
* Copyright 2010-2015 Renesas Electronics Corporation
|
||||
*
|
||||
* 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/device.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/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
/* I2C Registers */
|
||||
#define I2C_OFS_IICACT0 0x00 /* start */
|
||||
#define I2C_OFS_IIC0 0x04 /* shift */
|
||||
#define I2C_OFS_IICC0 0x08 /* control */
|
||||
#define I2C_OFS_SVA0 0x0c /* slave address */
|
||||
#define I2C_OFS_IICCL0 0x10 /* clock select */
|
||||
#define I2C_OFS_IICX0 0x14 /* extension */
|
||||
#define I2C_OFS_IICS0 0x18 /* status */
|
||||
#define I2C_OFS_IICSE0 0x1c /* status For emulation */
|
||||
#define I2C_OFS_IICF0 0x20 /* IIC flag */
|
||||
|
||||
/* I2C IICACT0 Masks */
|
||||
#define I2C_BIT_IICE0 0x0001
|
||||
|
||||
/* I2C IICC0 Masks */
|
||||
#define I2C_BIT_LREL0 0x0040
|
||||
#define I2C_BIT_WREL0 0x0020
|
||||
#define I2C_BIT_SPIE0 0x0010
|
||||
#define I2C_BIT_WTIM0 0x0008
|
||||
#define I2C_BIT_ACKE0 0x0004
|
||||
#define I2C_BIT_STT0 0x0002
|
||||
#define I2C_BIT_SPT0 0x0001
|
||||
|
||||
/* I2C IICCL0 Masks */
|
||||
#define I2C_BIT_SMC0 0x0008
|
||||
#define I2C_BIT_DFC0 0x0004
|
||||
|
||||
/* I2C IICSE0 Masks */
|
||||
#define I2C_BIT_MSTS0 0x0080
|
||||
#define I2C_BIT_ALD0 0x0040
|
||||
#define I2C_BIT_EXC0 0x0020
|
||||
#define I2C_BIT_COI0 0x0010
|
||||
#define I2C_BIT_TRC0 0x0008
|
||||
#define I2C_BIT_ACKD0 0x0004
|
||||
#define I2C_BIT_STD0 0x0002
|
||||
#define I2C_BIT_SPD0 0x0001
|
||||
|
||||
/* I2C IICF0 Masks */
|
||||
#define I2C_BIT_STCF 0x0080
|
||||
#define I2C_BIT_IICBSY 0x0040
|
||||
#define I2C_BIT_STCEN 0x0002
|
||||
#define I2C_BIT_IICRSV 0x0001
|
||||
|
||||
struct em_i2c_device {
|
||||
void __iomem *base;
|
||||
struct i2c_adapter adap;
|
||||
struct completion msg_done;
|
||||
struct clk *sclk;
|
||||
};
|
||||
|
||||
static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
|
||||
{
|
||||
writeb((readb(priv->base + reg) & ~clear) | set, priv->base + reg);
|
||||
}
|
||||
|
||||
static int em_i2c_wait_for_event(struct em_i2c_device *priv)
|
||||
{
|
||||
unsigned long time_left;
|
||||
int status;
|
||||
|
||||
reinit_completion(&priv->msg_done);
|
||||
|
||||
time_left = wait_for_completion_timeout(&priv->msg_done, priv->adap.timeout);
|
||||
|
||||
if (!time_left)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
status = readb(priv->base + I2C_OFS_IICSE0);
|
||||
return status & I2C_BIT_ALD0 ? -EAGAIN : status;
|
||||
}
|
||||
|
||||
static void em_i2c_stop(struct em_i2c_device *priv)
|
||||
{
|
||||
/* Send Stop condition */
|
||||
em_clear_set_bit(priv, 0, I2C_BIT_SPT0 | I2C_BIT_SPIE0, I2C_OFS_IICC0);
|
||||
|
||||
/* Wait for stop condition */
|
||||
em_i2c_wait_for_event(priv);
|
||||
}
|
||||
|
||||
static void em_i2c_reset(struct i2c_adapter *adap)
|
||||
{
|
||||
struct em_i2c_device *priv = i2c_get_adapdata(adap);
|
||||
int retr;
|
||||
|
||||
/* If I2C active */
|
||||
if (readb(priv->base + I2C_OFS_IICACT0) & I2C_BIT_IICE0) {
|
||||
/* Disable I2C operation */
|
||||
writeb(0, priv->base + I2C_OFS_IICACT0);
|
||||
|
||||
retr = 1000;
|
||||
while (readb(priv->base + I2C_OFS_IICACT0) == 1 && retr)
|
||||
retr--;
|
||||
WARN_ON(retr == 0);
|
||||
}
|
||||
|
||||
/* Transfer mode set */
|
||||
writeb(I2C_BIT_DFC0, priv->base + I2C_OFS_IICCL0);
|
||||
|
||||
/* Can Issue start without detecting a stop, Reservation disabled. */
|
||||
writeb(I2C_BIT_STCEN | I2C_BIT_IICRSV, priv->base + I2C_OFS_IICF0);
|
||||
|
||||
/* I2C enable, 9 bit interrupt mode */
|
||||
writeb(I2C_BIT_WTIM0, priv->base + I2C_OFS_IICC0);
|
||||
|
||||
/* Enable I2C operation */
|
||||
writeb(I2C_BIT_IICE0, priv->base + I2C_OFS_IICACT0);
|
||||
|
||||
retr = 1000;
|
||||
while (readb(priv->base + I2C_OFS_IICACT0) == 0 && retr)
|
||||
retr--;
|
||||
WARN_ON(retr == 0);
|
||||
}
|
||||
|
||||
static int __em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int stop)
|
||||
{
|
||||
struct em_i2c_device *priv = i2c_get_adapdata(adap);
|
||||
int count, status, read = !!(msg->flags & I2C_M_RD);
|
||||
|
||||
/* Send start condition */
|
||||
em_clear_set_bit(priv, 0, I2C_BIT_ACKE0 | I2C_BIT_WTIM0, I2C_OFS_IICC0);
|
||||
em_clear_set_bit(priv, 0, I2C_BIT_STT0, I2C_OFS_IICC0);
|
||||
|
||||
/* Send slave address and R/W type */
|
||||
writeb((msg->addr << 1) | read, priv->base + I2C_OFS_IIC0);
|
||||
|
||||
/* Wait for transaction */
|
||||
status = em_i2c_wait_for_event(priv);
|
||||
if (status < 0)
|
||||
goto out_reset;
|
||||
|
||||
/* Received NACK (result of setting slave address and R/W) */
|
||||
if (!(status & I2C_BIT_ACKD0)) {
|
||||
em_i2c_stop(priv);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Extra setup for read transactions */
|
||||
if (read) {
|
||||
/* 8 bit interrupt mode */
|
||||
em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0, I2C_OFS_IICC0);
|
||||
em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0, I2C_OFS_IICC0);
|
||||
|
||||
/* Wait for transaction */
|
||||
status = em_i2c_wait_for_event(priv);
|
||||
if (status < 0)
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
/* Send / receive data */
|
||||
for (count = 0; count < msg->len; count++) {
|
||||
if (read) { /* Read transaction */
|
||||
msg->buf[count] = readb(priv->base + I2C_OFS_IIC0);
|
||||
em_clear_set_bit(priv, 0, I2C_BIT_WREL0, I2C_OFS_IICC0);
|
||||
|
||||
} else { /* Write transaction */
|
||||
/* Received NACK */
|
||||
if (!(status & I2C_BIT_ACKD0)) {
|
||||
em_i2c_stop(priv);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Write data */
|
||||
writeb(msg->buf[count], priv->base + I2C_OFS_IIC0);
|
||||
}
|
||||
|
||||
/* Wait for R/W transaction */
|
||||
status = em_i2c_wait_for_event(priv);
|
||||
if (status < 0)
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
if (stop)
|
||||
em_i2c_stop(priv);
|
||||
|
||||
return count;
|
||||
|
||||
out_reset:
|
||||
em_i2c_reset(adap);
|
||||
out:
|
||||
return status < 0 ? status : -ENXIO;
|
||||
}
|
||||
|
||||
static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct em_i2c_device *priv = i2c_get_adapdata(adap);
|
||||
int ret, i;
|
||||
|
||||
if (readb(priv->base + I2C_OFS_IICF0) & I2C_BIT_IICBSY)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = __em_i2c_xfer(adap, &msgs[i], (i == (num - 1)));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C transfer completed */
|
||||
return num;
|
||||
}
|
||||
|
||||
static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id)
|
||||
{
|
||||
struct em_i2c_device *priv = dev_id;
|
||||
|
||||
complete(&priv->msg_done);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static u32 em_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm em_i2c_algo = {
|
||||
.master_xfer = em_i2c_xfer,
|
||||
.functionality = em_i2c_func,
|
||||
};
|
||||
|
||||
static int em_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct em_i2c_device *priv;
|
||||
struct resource *r;
|
||||
int irq, ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(&pdev->dev, r);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
strlcpy(priv->adap.name, "EMEV2 I2C", sizeof(priv->adap.name));
|
||||
|
||||
priv->sclk = devm_clk_get(&pdev->dev, "sclk");
|
||||
if (IS_ERR(priv->sclk))
|
||||
return PTR_ERR(priv->sclk);
|
||||
|
||||
clk_prepare_enable(priv->sclk);
|
||||
|
||||
priv->adap.timeout = msecs_to_jiffies(100);
|
||||
priv->adap.retries = 5;
|
||||
priv->adap.dev.parent = &pdev->dev;
|
||||
priv->adap.algo = &em_i2c_algo;
|
||||
priv->adap.owner = THIS_MODULE;
|
||||
priv->adap.dev.of_node = pdev->dev.of_node;
|
||||
|
||||
init_completion(&priv->msg_done);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
i2c_set_adapdata(&priv->adap, priv);
|
||||
|
||||
em_i2c_reset(&priv->adap);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_irq(&pdev->dev, irq, em_i2c_irq_handler, 0,
|
||||
"em_i2c", priv);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
ret = i2c_add_adapter(&priv->adap);
|
||||
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr, irq);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(priv->sclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int em_i2c_remove(struct platform_device *dev)
|
||||
{
|
||||
struct em_i2c_device *priv = platform_get_drvdata(dev);
|
||||
|
||||
i2c_del_adapter(&priv->adap);
|
||||
clk_disable_unprepare(priv->sclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id em_i2c_ids[] = {
|
||||
{ .compatible = "renesas,iic-emev2", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver em_i2c_driver = {
|
||||
.probe = em_i2c_probe,
|
||||
.remove = em_i2c_remove,
|
||||
.driver = {
|
||||
.name = "em-i2c",
|
||||
.of_match_table = em_i2c_ids,
|
||||
}
|
||||
};
|
||||
module_platform_driver(em_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("EMEV2 I2C bus driver");
|
||||
MODULE_AUTHOR("Ian Molton and Wolfram Sang <wsa@sang-engineering.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DEVICE_TABLE(of, em_i2c_ids);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user