Watch
1
Fork
You've already forked kernel_a52xq
0
mirror of https://github.com/a52xq-dev/kernel.git synced 2026-10-18 21:58:11 +07:00

Merge branch 'i2c/for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:

 - the first series of making i2c_device_id optional instead of
   mandatory (in favor of alternatives like of_device_id).

   This involves adding a new probe callback (probe_new) which removes
   some peculiarities I2C had for a long time now. The new probe is
   matching the other subsystems now and the old one will be removed
   once all users are converted. It is expected to take a while but
   there is ongoing interest in that.

 - SMBus Host Notify introduced 4.9 got refactored. They are now using
   interrupts instead of the alert callback which solves multiple
   issues.

 - new drivers for iMX LowPower I2C, Mellanox CPLD and its I2C mux

 - significant refactoring for bcm2835 driver

 - the usual set of driver updates and improvements

* 'i2c/for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (46 commits)
  i2c: fsl-lpi2c: read lpi2c fifo size in probe()
  i2c: octeon: thunderx: Remove double-check after interrupt
  i2c: octeon: thunderx: TWSI software reset in recovery
  i2c: cadence: Allow Cadence I2C to be selected for Cadence Xtensa CPUs
  i2c: sh_mobile: Add per-Generation fallback bindings
  i2c: rcar: Add per-Generation fallback bindings
  i2c: imx-lpi2c: add low power i2c bus driver
  dt-bindings: i2c: imx-lpi2c: add devicetree bindings
  i2c: designware-pcidrv: Add 10bit address feature to medfield/merrifield
  i2c: pxa: Add support for the I2C units found in Armada 3700
  i2c: pxa: Add definition of fast and high speed modes via the regs layout
  dt-bindings: i2c: pxa: Update the documentation for the Armada 3700
  i2c: qup: support SMBus block read
  i2c: qup: add ACPI support
  i2c: designware: Consolidate default functionality bits
  i2c: i2c-mux-gpio: update mux with gpiod_set_array_value_cansleep
  i2c: mux: pca954x: Add ACPI support for pca954x
  i2c: use an IRQ to report Host Notify events, not alert
  i2c: i801: remove SMBNTFDDAT reads as they always seem to return 0
  i2c: i801: use the BIT() macro for FEATURES_* also
  ...
This commit is contained in:
Linus Torvalds 2016-12-15 12:56:35 -08:00
commit 8600b697cd
42 changed files with 2264 additions and 429 deletions

View file

@ -0,0 +1,20 @@
* Freescale Low Power Inter IC (LPI2C) for i.MX
Required properties:
- compatible :
- "fsl,imx7ulp-lpi2c" for LPI2C compatible with the one integrated on i.MX7ULP soc
- "fsl,imx8dv-lpi2c" for LPI2C compatible with the one integrated on i.MX8DV soc
- reg : address and length of the lpi2c master registers
- interrupt-parent : core interrupt controller
- interrupts : lpi2c interrupt
- clocks : lpi2c clock specifier
Examples:
lpi2c7: lpi2c7@40A50000 {
compatible = "fsl,imx8dv-lpi2c";
reg = <0x40A50000 0x10000>;
interrupt-parent = <&intc>;
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX7ULP_CLK_LPI2C7>;
};

View file

@ -7,6 +7,7 @@ Required properties :
compatible processor, e.g. pxa168, pxa910, mmp2, mmp3.
For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required
as shown in the example below.
For the Armada 3700, the compatible should be "marvell,armada-3700-i2c".
Recommended properties :

View file

@ -1,17 +1,25 @@
I2C for R-Car platforms
Required properties:
- compatible: Must be one of
"renesas,i2c-rcar"
"renesas,i2c-r8a7778"
"renesas,i2c-r8a7779"
"renesas,i2c-r8a7790"
"renesas,i2c-r8a7791"
"renesas,i2c-r8a7792"
"renesas,i2c-r8a7793"
"renesas,i2c-r8a7794"
"renesas,i2c-r8a7795"
"renesas,i2c-r8a7796"
- compatible:
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
"renesas,i2c-r8a7791" if the device is a part of a R8A7791 SoC.
"renesas,i2c-r8a7792" if the device is a part of a R8A7792 SoC.
"renesas,i2c-r8a7793" if the device is a part of a R8A7793 SoC.
"renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC.
"renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC.
"renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC.
"renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device.
"renesas,rcar-gen2-i2c" for a generic R-Car Gen2 compatible device.
"renesas,rcar-gen3-i2c" for a generic R-Car Gen3 compatible device.
"renesas,i2c-rcar" (deprecated)
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first followed
by the generic version.
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt specifier.
@ -33,7 +41,7 @@ Examples :
i2c0: i2c@e6508000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "renesas,i2c-r8a7791";
compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
reg = <0 0xe6508000 0 0x40>;
interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_I2C0>;

View file

@ -1,8 +1,7 @@
Device tree configuration for Renesas IIC (sh_mobile) driver
Required properties:
- compatible : "renesas,iic-<soctype>". "renesas,rmobile-iic" as fallback
Examples with soctypes are:
- compatible :
- "renesas,iic-r8a73a4" (R-Mobile APE6)
- "renesas,iic-r8a7740" (R-Mobile A1)
- "renesas,iic-r8a7790" (R-Car H2)
@ -12,6 +11,17 @@ Required properties:
- "renesas,iic-r8a7794" (R-Car E2)
- "renesas,iic-r8a7795" (R-Car H3)
- "renesas,iic-sh73a0" (SH-Mobile AG5)
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 compatible device)
- "renesas,rcar-gen3-iic" (generic R-Car Gen3 compatible device)
- "renesas,rmobile-iic" (generic device)
When compatible with a generic R-Car version, nodes
must list the SoC-specific version corresponding to
the platform first followed by the generic R-Car
version.
renesas,rmobile-iic must always follow.
- reg : address start and address range size of device
- interrupts : interrupt of device
- clocks : clock for device
@ -31,7 +41,8 @@ Pinctrl properties might be needed, too. See there.
Example:
iic0: i2c@e6500000 {
compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic";
compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic",
"renesas,rmobile-iic";
reg = <0 0xe6500000 0 0x425>;
interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_IIC0>;

View file

@ -0,0 +1,47 @@
Driver i2c-mlxcpld
Author: Michael Shych <michaelsh@mellanox.com>
This is the Mellanox I2C controller logic, implemented in Lattice CPLD
device.
Device supports:
- Master mode.
- One physical bus.
- Polling mode.
This controller is equipped within the next Mellanox systems:
"msx6710", "msx6720", "msb7700", "msn2700", "msx1410", "msn2410", "msb7800",
"msn2740", "msn2100".
The next transaction types are supported:
- Receive Byte/Block.
- Send Byte/Block.
- Read Byte/Block.
- Write Byte/Block.
Registers:
CTRL 0x1 - control reg.
Resets all the registers.
HALF_CYC 0x4 - cycle reg.
Configure the width of I2C SCL half clock cycle (in 4 LPC_CLK
units).
I2C_HOLD 0x5 - hold reg.
OE (output enable) is delayed by value set to this register
(in LPC_CLK units)
CMD 0x6 - command reg.
Bit 0, 0 = write, 1 = read.
Bits [7:1] - the 7bit Address of the I2C device.
It should be written last as it triggers an I2C transaction.
NUM_DATA 0x7 - data size reg.
Number of data bytes to write in read transaction
NUM_ADDR 0x8 - address reg.
Number of address bytes to write in read transaction.
STATUS 0x9 - status reg.
Bit 0 - transaction is completed.
Bit 4 - ACK/NACK.
DATAx 0xa - 0x54 - 68 bytes data buffer regs.
For write transaction address is specified in four first bytes
(DATA1 - DATA4), data starting from DATA4.
For read transactions address is sent in a separate transaction and
specified in the four first bytes (DATA0 - DATA3). Data is read
starting from DATA0.

View file

@ -200,10 +200,14 @@ alerting device's address.
[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P]
This is implemented in the following way in the Linux kernel:
* I2C bus drivers which support SMBus Host Notify should call
i2c_setup_smbus_host_notify() to setup SMBus Host Notify support.
* I2C drivers for devices which can trigger SMBus Host Notify should implement
the optional alert() callback.
* I2C bus drivers which support SMBus Host Notify should report
I2C_FUNC_SMBUS_HOST_NOTIFY.
* I2C bus drivers trigger SMBus Host Notify by a call to
i2c_handle_smbus_host_notify().
* I2C drivers for devices which can trigger SMBus Host Notify will have
client->irq assigned to a Host Notify IRQ if noone else specified an other.
There is currently no way to retrieve the data parameter from the client.
Packet Error Checking (PEC)

View file

@ -8023,6 +8023,15 @@ W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlxsw/
MELLANOX MLXCPLD I2C AND MUX DRIVER
M: Vadim Pasternak <vadimp@mellanox.com>
M: Michael Shych <michaelsh@mellanox.com>
L: linux-i2c@vger.kernel.org
S: Supported
F: drivers/i2c/busses/i2c-mlxcpld.c
F: drivers/i2c/muxes/i2c-mux-mlxcpld.c
F: Documentation/i2c/busses/i2c-mlxcpld
MELLANOX MLXCPLD LED DRIVER
M: Vadim Pasternak <vadimp@mellanox.com>
L: linux-leds@vger.kernel.org

View file

@ -7,6 +7,7 @@ menu "I2C support"
config I2C
tristate "I2C support"
select RT_MUTEXES
select IRQ_DOMAIN
---help---
I2C (pronounce: I-squared-C) is a slow serial bus protocol used in
many micro controller applications and developed by Philips. SMBus,

View file

@ -426,7 +426,7 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
config I2C_CADENCE
tristate "Cadence I2C Controller"
depends on ARCH_ZYNQ || ARM64
depends on ARCH_ZYNQ || ARM64 || XTENSA
help
Say yes here to select Cadence I2C Host Controller. This controller is
e.g. used by Xilinx Zynq.
@ -597,6 +597,16 @@ config I2C_IMX
This driver can also be built as a module. If so, the module
will be called i2c-imx.
config I2C_IMX_LPI2C
tristate "IMX Low Power I2C interface"
depends on ARCH_MXC || COMPILE_TEST
help
Say Y here if you want to use the Low Power IIC bus controller
on the Freescale i.MX processors.
This driver can also be built as a module. If so, the module
will be called i2c-imx-lpi2c.
config I2C_IOP3XX
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
@ -763,7 +773,7 @@ config I2C_PUV3
config I2C_PXA
tristate "Intel PXA2XX I2C adapter"
depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF)
depends on ARCH_PXA || ARCH_MMP || ARCH_MVEBU || (X86_32 && PCI && OF)
help
If you have devices in the PXA I2C bus, say yes to this option.
This driver can also be built as a module. If so, the module
@ -1150,6 +1160,17 @@ config I2C_ELEKTOR
This support is also available as a module. If so, the module
will be called i2c-elektor.
config I2C_MLXCPLD
tristate "Mellanox I2C driver"
depends on X86_64
help
This exposes the Mellanox platform I2C busses to the linux I2C layer
for X86 based systems.
Controller is implemented as CPLD logic.
This driver can also be built as a module. If so, the module will be
called as i2c-mlxcpld.
config I2C_PCA_ISA
tristate "PCA9564/PCA9665 on an ISA bus"
depends on ISA

View file

@ -56,6 +56,7 @@ obj-$(CONFIG_I2C_HIX5HD2) += i2c-hix5hd2.o
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_IMX_LPI2C) += i2c-imx-lpi2c.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
@ -116,6 +117,7 @@ obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o
obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o
obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o
obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o

View file

@ -489,7 +489,7 @@ static const struct i2c_algorithm axxia_i2c_algo = {
.functionality = axxia_i2c_func,
};
static struct i2c_adapter_quirks axxia_i2c_quirks = {
static const struct i2c_adapter_quirks axxia_i2c_quirks = {
.max_read_len = 255,
.max_write_len = 255,
};

View file

@ -395,7 +395,7 @@ static const struct i2c_algorithm bcm_iproc_algo = {
.functionality = bcm_iproc_i2c_functionality,
};
static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
static const 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,
};

View file

@ -50,20 +50,19 @@
#define BCM2835_I2C_S_CLKT BIT(9)
#define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */
#define BCM2835_I2C_BITMSK_S 0x03FF
#define BCM2835_I2C_CDIV_MIN 0x0002
#define BCM2835_I2C_CDIV_MAX 0xFFFE
#define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000))
struct bcm2835_i2c_dev {
struct device *dev;
void __iomem *regs;
struct clk *clk;
int irq;
u32 bus_clk_rate;
struct i2c_adapter adapter;
struct completion completion;
struct i2c_msg *curr_msg;
int num_msgs;
u32 msg_err;
u8 *msg_buf;
size_t msg_buf_remaining;
@ -80,6 +79,30 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
return readl(i2c_dev->regs + reg);
}
static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
{
u32 divider;
divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
i2c_dev->bus_clk_rate);
/*
* Per the datasheet, the register is always interpreted as an even
* number, by rounding down. In other words, the LSB is ignored. So,
* if the LSB is set, increment the divider to avoid any issue.
*/
if (divider & 1)
divider++;
if ((divider < BCM2835_I2C_CDIV_MIN) ||
(divider > BCM2835_I2C_CDIV_MAX)) {
dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
return -EINVAL;
}
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
return 0;
}
static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
{
u32 val;
@ -110,106 +133,159 @@ static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev)
}
}
/*
* Repeated Start Condition (Sr)
* The BCM2835 ARM Peripherals datasheet mentions a way to trigger a Sr when it
* talks about reading from a slave with 10 bit address. This is achieved by
* issuing a write, poll the I2CS.TA flag and wait for it to be set, and then
* issue a read.
* A comment in https://github.com/raspberrypi/linux/issues/254 shows how the
* firmware actually does it using polling and says that it's a workaround for
* a problem in the state machine.
* It turns out that it is possible to use the TXW interrupt to know when the
* transfer is active, provided the FIFO has not been prefilled.
*/
static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev)
{
u32 c = BCM2835_I2C_C_ST | BCM2835_I2C_C_I2CEN;
struct i2c_msg *msg = i2c_dev->curr_msg;
bool last_msg = (i2c_dev->num_msgs == 1);
if (!i2c_dev->num_msgs)
return;
i2c_dev->num_msgs--;
i2c_dev->msg_buf = msg->buf;
i2c_dev->msg_buf_remaining = msg->len;
if (msg->flags & I2C_M_RD)
c |= BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR;
else
c |= BCM2835_I2C_C_INTT;
if (last_msg)
c |= BCM2835_I2C_C_INTD;
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
}
/*
* Note about I2C_C_CLEAR on error:
* The I2C_C_CLEAR on errors will take some time to resolve -- if you were in
* non-idle state and I2C_C_READ, it sets an abort_rx flag and runs through
* the state machine to send a NACK and a STOP. Since we're setting CLEAR
* without I2CEN, that NACK will be hanging around queued up for next time
* we start the engine.
*/
static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
{
struct bcm2835_i2c_dev *i2c_dev = data;
u32 val, err;
val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
val &= BCM2835_I2C_BITMSK_S;
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val);
err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
if (err) {
i2c_dev->msg_err = err;
complete(&i2c_dev->completion);
return IRQ_HANDLED;
}
if (val & BCM2835_I2C_S_RXD) {
bcm2835_drain_rxfifo(i2c_dev);
if (!(val & BCM2835_I2C_S_DONE))
return IRQ_HANDLED;
goto complete;
}
if (val & BCM2835_I2C_S_DONE) {
if (i2c_dev->msg_buf_remaining)
if (i2c_dev->curr_msg->flags & I2C_M_RD) {
bcm2835_drain_rxfifo(i2c_dev);
val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
}
if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining)
i2c_dev->msg_err = BCM2835_I2C_S_LEN;
else
i2c_dev->msg_err = 0;
complete(&i2c_dev->completion);
goto complete;
}
if (val & BCM2835_I2C_S_TXW) {
if (!i2c_dev->msg_buf_remaining) {
i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
goto complete;
}
bcm2835_fill_txfifo(i2c_dev);
if (i2c_dev->num_msgs && !i2c_dev->msg_buf_remaining) {
i2c_dev->curr_msg++;
bcm2835_i2c_start_transfer(i2c_dev);
}
return IRQ_HANDLED;
}
if (val & BCM2835_I2C_S_TXD) {
bcm2835_fill_txfifo(i2c_dev);
if (val & BCM2835_I2C_S_RXR) {
if (!i2c_dev->msg_buf_remaining) {
i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
goto complete;
}
bcm2835_drain_rxfifo(i2c_dev);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
struct i2c_msg *msg)
{
u32 c;
unsigned long time_left;
i2c_dev->msg_buf = msg->buf;
i2c_dev->msg_buf_remaining = msg->len;
reinit_completion(&i2c_dev->completion);
complete:
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT |
BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE);
complete(&i2c_dev->completion);
if (msg->flags & I2C_M_RD) {
c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR;
} else {
c = BCM2835_I2C_C_INTT;
bcm2835_fill_txfifo(i2c_dev);
}
c |= BCM2835_I2C_C_ST | BCM2835_I2C_C_INTD | BCM2835_I2C_C_I2CEN;
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
time_left = wait_for_completion_timeout(&i2c_dev->completion,
BCM2835_I2C_TIMEOUT);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
if (!time_left) {
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
return -ETIMEDOUT;
}
if (likely(!i2c_dev->msg_err))
return 0;
if ((i2c_dev->msg_err & BCM2835_I2C_S_ERR) &&
(msg->flags & I2C_M_IGNORE_NAK))
return 0;
dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
return -EREMOTEIO;
else
return -EIO;
return IRQ_HANDLED;
}
static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
int num)
{
struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
int i;
int ret = 0;
unsigned long time_left;
int i, ret;
for (i = 0; i < num; i++) {
ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[i]);
if (ret)
break;
for (i = 0; i < (num - 1); i++)
if (msgs[i].flags & I2C_M_RD) {
dev_warn_once(i2c_dev->dev,
"only one read message supported, has to be last\n");
return -EOPNOTSUPP;
}
ret = bcm2835_i2c_set_divider(i2c_dev);
if (ret)
return ret;
i2c_dev->curr_msg = msgs;
i2c_dev->num_msgs = num;
reinit_completion(&i2c_dev->completion);
bcm2835_i2c_start_transfer(i2c_dev);
time_left = wait_for_completion_timeout(&i2c_dev->completion,
adap->timeout);
if (!time_left) {
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
BCM2835_I2C_C_CLEAR);
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
return -ETIMEDOUT;
}
return ret ?: i;
if (!i2c_dev->msg_err)
return num;
dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
return -EREMOTEIO;
return -EIO;
}
static u32 bcm2835_i2c_func(struct i2c_adapter *adap)
@ -235,7 +311,6 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev;
struct resource *mem, *irq;
u32 bus_clk_rate, divider;
int ret;
struct i2c_adapter *adap;
@ -259,28 +334,13 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&bus_clk_rate);
&i2c_dev->bus_clk_rate);
if (ret < 0) {
dev_warn(&pdev->dev,
"Could not read clock-frequency property\n");
bus_clk_rate = 100000;
i2c_dev->bus_clk_rate = 100000;
}
divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), bus_clk_rate);
/*
* Per the datasheet, the register is always interpreted as an even
* number, by rounding down. In other words, the LSB is ignored. So,
* if the LSB is set, increment the divider to avoid any issue.
*/
if (divider & 1)
divider++;
if ((divider < BCM2835_I2C_CDIV_MIN) ||
(divider > BCM2835_I2C_CDIV_MAX)) {
dev_err(&pdev->dev, "Invalid clock-frequency\n");
return -ENODEV;
}
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "No IRQ resource\n");

View file

@ -536,6 +536,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
intr_mask = DW_IC_INTR_DEFAULT_MASK;
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
u32 flags = msgs[dev->msg_write_idx].flags;
/*
* if target address has changed, we need to
* reprogram the target address in the i2c
@ -581,8 +583,15 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
* detected from the registers so we set it always
* when writing/reading the last byte.
*/
/*
* i2c-core.c always sets the buffer length of
* I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will
* be adjusted when receiving the first byte.
* Thus we can't stop the transaction here.
*/
if (dev->msg_write_idx == dev->msgs_num - 1 &&
buf_len == 1)
buf_len == 1 && !(flags & I2C_M_RECV_LEN))
cmd |= BIT(9);
if (need_restart) {
@ -607,7 +616,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
dev->tx_buf = buf;
dev->tx_buf_len = buf_len;
if (buf_len > 0) {
/*
* Because we don't know the buffer length in the
* I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
* the transaction here.
*/
if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
/* more bytes to be written */
dev->status |= STATUS_WRITE_IN_PROGRESS;
break;
@ -628,6 +642,24 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
}
static u8
i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
{
struct i2c_msg *msgs = dev->msgs;
u32 flags = msgs[dev->msg_read_idx].flags;
/*
* Adjust the buffer length and mask the flag
* after receiving the first byte.
*/
len += (flags & I2C_CLIENT_PEC) ? 2 : 1;
dev->tx_buf_len = len - min_t(u8, len, dev->rx_outstanding);
msgs[dev->msg_read_idx].len = len;
msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
return len;
}
static void
i2c_dw_read(struct dw_i2c_dev *dev)
{
@ -652,7 +684,15 @@ i2c_dw_read(struct dw_i2c_dev *dev)
rx_valid = dw_readl(dev, DW_IC_RXFLR);
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
*buf++ = dw_readl(dev, DW_IC_DATA_CMD);
u32 flags = msgs[dev->msg_read_idx].flags;
*buf = dw_readl(dev, DW_IC_DATA_CMD);
/* Ensure length byte is a valid value */
if (flags & I2C_M_RECV_LEN &&
*buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
len = i2c_dw_recv_len(dev, *buf);
}
buf++;
dev->rx_outstanding--;
}

View file

@ -22,6 +22,14 @@
*
*/
#include <linux/i2c.h>
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_BLOCK_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
#define DW_IC_CON_MASTER 0x1
#define DW_IC_CON_SPEED_STD 0x2

View file

@ -71,12 +71,6 @@ struct dw_pci_controller {
DW_IC_CON_SLAVE_DISABLE | \
DW_IC_CON_RESTART_EN)
#define DW_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
/* Merrifield HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg mrfld_config = {
.ss_hcnt = 0x2f8,
@ -147,6 +141,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.functionality = I2C_FUNC_10BIT_ADDR,
.clk_khz = 25000,
.setup = mfld_setup,
},
@ -155,6 +150,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 64,
.rx_fifo_depth = 64,
.functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &mrfld_config,
.setup = mrfld_setup,
},
@ -249,7 +245,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
}
dev->functionality = controller->functionality |
DW_DEFAULT_FUNCTIONALITY;
DW_IC_DEFAULT_FUNCTIONALITY;
dev->master_cfg = controller->bus_cfg;
if (controller->scl_sda_cfg) {

View file

@ -176,9 +176,6 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
dev->irq = irq;
platform_set_drvdata(pdev, dev);
/* fast mode by default because of legacy reasons */
dev->clk_freq = 400000;
if (pdata) {
dev->clk_freq = pdata->i2c_scl_freq;
} else {
@ -193,8 +190,16 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
}
acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
if (acpi_speed)
dev->clk_freq = acpi_speed;
/*
* Find bus speed from the "clock-frequency" device property, ACPI
* or by using fast mode if neither is set.
*/
if (acpi_speed && dev->clk_freq)
dev->clk_freq = min(dev->clk_freq, acpi_speed);
else if (acpi_speed || dev->clk_freq)
dev->clk_freq = max(dev->clk_freq, acpi_speed);
else
dev->clk_freq = 400000;
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
@ -214,13 +219,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
if (r)
return r;
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
DW_IC_CON_RESTART_EN;

View file

@ -182,7 +182,7 @@ static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
.functionality = dln2_i2c_func,
};
static struct i2c_adapter_quirks dln2_i2c_quirks = {
static const struct i2c_adapter_quirks dln2_i2c_quirks = {
.max_read_len = DLN2_I2C_MAX_XFER_SIZE,
.max_write_len = DLN2_I2C_MAX_XFER_SIZE,
};

View file

@ -118,7 +118,6 @@
#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */
#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */
#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */
#define SMBNTFDDAT(p) (22 + (p)->smba) /* ICH3 and later */
/* PCI Address Constants */
#define SMBBAR 4
@ -137,27 +136,27 @@
#define SBREG_SMBCTRL 0xc6000c
/* Host status bits for SMBPCISTS */
#define SMBPCISTS_INTS 0x08
#define SMBPCISTS_INTS BIT(3)
/* Control bits for SMBPCICTL */
#define SMBPCICTL_INTDIS 0x0400
#define SMBPCICTL_INTDIS BIT(10)
/* Host configuration bits for SMBHSTCFG */
#define SMBHSTCFG_HST_EN 1
#define SMBHSTCFG_SMB_SMI_EN 2
#define SMBHSTCFG_I2C_EN 4
#define SMBHSTCFG_SPD_WD 0x10
#define SMBHSTCFG_HST_EN BIT(0)
#define SMBHSTCFG_SMB_SMI_EN BIT(1)
#define SMBHSTCFG_I2C_EN BIT(2)
#define SMBHSTCFG_SPD_WD BIT(4)
/* TCO configuration bits for TCOCTL */
#define TCOCTL_EN 0x0100
#define TCOCTL_EN BIT(8)
/* Auxiliary status register bits, ICH4+ only */
#define SMBAUXSTS_CRCE 1
#define SMBAUXSTS_STCO 2
#define SMBAUXSTS_CRCE BIT(0)
#define SMBAUXSTS_STCO BIT(1)
/* Auxiliary control register bits, ICH4+ only */
#define SMBAUXCTL_CRC 1
#define SMBAUXCTL_E32B 2
#define SMBAUXCTL_CRC BIT(0)
#define SMBAUXCTL_E32B BIT(1)
/* Other settings */
#define MAX_RETRIES 400
@ -172,27 +171,27 @@
#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
/* I801 Host Control register bits */
#define SMBHSTCNT_INTREN 0x01
#define SMBHSTCNT_KILL 0x02
#define SMBHSTCNT_LAST_BYTE 0x20
#define SMBHSTCNT_START 0x40
#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */
#define SMBHSTCNT_INTREN BIT(0)
#define SMBHSTCNT_KILL BIT(1)
#define SMBHSTCNT_LAST_BYTE BIT(5)
#define SMBHSTCNT_START BIT(6)
#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */
/* I801 Hosts Status register bits */
#define SMBHSTSTS_BYTE_DONE 0x80
#define SMBHSTSTS_INUSE_STS 0x40
#define SMBHSTSTS_SMBALERT_STS 0x20
#define SMBHSTSTS_FAILED 0x10
#define SMBHSTSTS_BUS_ERR 0x08
#define SMBHSTSTS_DEV_ERR 0x04
#define SMBHSTSTS_INTR 0x02
#define SMBHSTSTS_HOST_BUSY 0x01
#define SMBHSTSTS_BYTE_DONE BIT(7)
#define SMBHSTSTS_INUSE_STS BIT(6)
#define SMBHSTSTS_SMBALERT_STS BIT(5)
#define SMBHSTSTS_FAILED BIT(4)
#define SMBHSTSTS_BUS_ERR BIT(3)
#define SMBHSTSTS_DEV_ERR BIT(2)
#define SMBHSTSTS_INTR BIT(1)
#define SMBHSTSTS_HOST_BUSY BIT(0)
/* Host Notify Status registers bits */
#define SMBSLVSTS_HST_NTFY_STS 1
/* Host Notify Status register bits */
#define SMBSLVSTS_HST_NTFY_STS BIT(0)
/* Host Notify Command registers bits */
#define SMBSLVCMD_HST_NTFY_INTREN 0x01
/* Host Notify Command register bits */
#define SMBSLVCMD_HST_NTFY_INTREN BIT(0)
#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
SMBHSTSTS_DEV_ERR)
@ -243,6 +242,7 @@ struct i801_priv {
struct i2c_adapter adapter;
unsigned long smba;
unsigned char original_hstcfg;
unsigned char original_slvcmd;
struct pci_dev *pci_dev;
unsigned int features;
@ -269,20 +269,17 @@ struct i801_priv {
*/
bool acpi_reserved;
struct mutex acpi_lock;
struct smbus_host_notify *host_notify;
};
#define SMBHSTNTFY_SIZE 8
#define FEATURE_SMBUS_PEC (1 << 0)
#define FEATURE_BLOCK_BUFFER (1 << 1)
#define FEATURE_BLOCK_PROC (1 << 2)
#define FEATURE_I2C_BLOCK_READ (1 << 3)
#define FEATURE_IRQ (1 << 4)
#define FEATURE_HOST_NOTIFY (1 << 5)
#define FEATURE_SMBUS_PEC BIT(0)
#define FEATURE_BLOCK_BUFFER BIT(1)
#define FEATURE_BLOCK_PROC BIT(2)
#define FEATURE_I2C_BLOCK_READ BIT(3)
#define FEATURE_IRQ BIT(4)
#define FEATURE_HOST_NOTIFY BIT(5)
/* Not really a feature, but it's convenient to handle it as such */
#define FEATURE_IDF (1 << 15)
#define FEATURE_TCO (1 << 16)
#define FEATURE_IDF BIT(15)
#define FEATURE_TCO BIT(16)
static const char *i801_feature_names[] = {
"SMBus PEC",
@ -582,12 +579,15 @@ static void i801_isr_byte_done(struct i801_priv *priv)
static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
{
unsigned short addr;
unsigned int data;
addr = inb_p(SMBNTFDADD(priv)) >> 1;
data = inw_p(SMBNTFDDAT(priv));
i2c_handle_smbus_host_notify(priv->host_notify, addr, data);
/*
* With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba)
* always returns 0. Our current implementation doesn't provide
* data, so we just ignore it.
*/
i2c_handle_smbus_host_notify(&priv->adapter, addr);
/* clear Host Notify bit and return */
outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
@ -950,23 +950,29 @@ static u32 i801_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_HOST_NOTIFY : 0);
}
static int i801_enable_host_notify(struct i2c_adapter *adapter)
static void i801_enable_host_notify(struct i2c_adapter *adapter)
{
struct i801_priv *priv = i2c_get_adapdata(adapter);
if (!(priv->features & FEATURE_HOST_NOTIFY))
return -ENOTSUPP;
return;
if (!priv->host_notify)
priv->host_notify = i2c_setup_smbus_host_notify(adapter);
if (!priv->host_notify)
return -ENOMEM;
priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd))
outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd,
SMBSLVCMD(priv));
outb_p(SMBSLVCMD_HST_NTFY_INTREN, SMBSLVCMD(priv));
/* clear Host Notify bit to allow a new notification */
outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
}
return 0;
static void i801_disable_host_notify(struct i801_priv *priv)
{
if (!(priv->features & FEATURE_HOST_NOTIFY))
return;
outb_p(priv->original_slvcmd, SMBSLVCMD(priv));
}
static const struct i2c_algorithm smbus_algorithm = {
@ -1633,14 +1639,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
return err;
}
/*
* Enable Host Notify for chips that supports it.
* It is done after i2c_add_adapter() so that we are sure the work queue
* is not used if i2c_add_adapter() fails.
*/
err = i801_enable_host_notify(&priv->adapter);
if (err && err != -ENOTSUPP)
dev_warn(&dev->dev, "Unable to enable SMBus Host Notify\n");
i801_enable_host_notify(&priv->adapter);
i801_probe_optional_slaves(priv);
/* We ignore errors - multiplexing is optional */
@ -1663,6 +1662,7 @@ static void i801_remove(struct pci_dev *dev)
pm_runtime_forbid(&dev->dev);
pm_runtime_get_noresume(&dev->dev);
i801_disable_host_notify(priv);
i801_del_mux(priv);
i2c_del_adapter(&priv->adapter);
i801_acpi_remove(priv);
@ -1690,11 +1690,8 @@ static int i801_resume(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct i801_priv *priv = pci_get_drvdata(pci_dev);
int err;
err = i801_enable_host_notify(&priv->adapter);
if (err && err != -ENOTSUPP)
dev_warn(dev, "Unable to enable SMBus Host Notify\n");
i801_enable_host_notify(&priv->adapter);
return 0;
}

View file

@ -0,0 +1,652 @@
/*
* This is i.MX low power i2c controller driver.
*
* Copyright 2016 Freescale Semiconductor, Inc.
*
* 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/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.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.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#define DRIVER_NAME "imx-lpi2c"
#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */
#define LPI2C_MCR 0x10 /* i2c contrl register */
#define LPI2C_MSR 0x14 /* i2c status register */
#define LPI2C_MIER 0x18 /* i2c interrupt enable */
#define LPI2C_MCFGR0 0x20 /* i2c master configuration */
#define LPI2C_MCFGR1 0x24 /* i2c master configuration */
#define LPI2C_MCFGR2 0x28 /* i2c master configuration */
#define LPI2C_MCFGR3 0x2C /* i2c master configuration */
#define LPI2C_MCCR0 0x48 /* i2c master clk configuration */
#define LPI2C_MCCR1 0x50 /* i2c master clk configuration */
#define LPI2C_MFCR 0x58 /* i2c master FIFO control */
#define LPI2C_MFSR 0x5C /* i2c master FIFO status */
#define LPI2C_MTDR 0x60 /* i2c master TX data register */
#define LPI2C_MRDR 0x70 /* i2c master RX data register */
/* i2c command */
#define TRAN_DATA 0X00
#define RECV_DATA 0X01
#define GEN_STOP 0X02
#define RECV_DISCARD 0X03
#define GEN_START 0X04
#define START_NACK 0X05
#define START_HIGH 0X06
#define START_HIGH_NACK 0X07
#define MCR_MEN BIT(0)
#define MCR_RST BIT(1)
#define MCR_DOZEN BIT(2)
#define MCR_DBGEN BIT(3)
#define MCR_RTF BIT(8)
#define MCR_RRF BIT(9)
#define MSR_TDF BIT(0)
#define MSR_RDF BIT(1)
#define MSR_SDF BIT(9)
#define MSR_NDF BIT(10)
#define MSR_ALF BIT(11)
#define MSR_MBF BIT(24)
#define MSR_BBF BIT(25)
#define MIER_TDIE BIT(0)
#define MIER_RDIE BIT(1)
#define MIER_SDIE BIT(9)
#define MIER_NDIE BIT(10)
#define MCFGR1_AUTOSTOP BIT(8)
#define MCFGR1_IGNACK BIT(9)
#define MRDR_RXEMPTY BIT(14)
#define I2C_CLK_RATIO 2
#define CHUNK_DATA 256
#define LPI2C_DEFAULT_RATE 100000
#define STARDARD_MAX_BITRATE 400000
#define FAST_MAX_BITRATE 1000000
#define FAST_PLUS_MAX_BITRATE 3400000
#define HIGHSPEED_MAX_BITRATE 5000000
enum lpi2c_imx_mode {
STANDARD, /* 100+Kbps */
FAST, /* 400+Kbps */
FAST_PLUS, /* 1.0+Mbps */
HS, /* 3.4+Mbps */
ULTRA_FAST, /* 5.0+Mbps */
};
enum lpi2c_imx_pincfg {
TWO_PIN_OD,
TWO_PIN_OO,
TWO_PIN_PP,
FOUR_PIN_PP,
};
struct lpi2c_imx_struct {
struct i2c_adapter adapter;
struct clk *clk;
void __iomem *base;
__u8 *rx_buf;
__u8 *tx_buf;
struct completion complete;
unsigned int msglen;
unsigned int delivered;
unsigned int block_data;
unsigned int bitrate;
unsigned int txfifosize;
unsigned int rxfifosize;
enum lpi2c_imx_mode mode;
};
static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
unsigned int enable)
{
writel(enable, lpi2c_imx->base + LPI2C_MIER);
}
static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned long orig_jiffies = jiffies;
unsigned int temp;
while (1) {
temp = readl(lpi2c_imx->base + LPI2C_MSR);
/* check for arbitration lost, clear if set */
if (temp & MSR_ALF) {
writel(temp, lpi2c_imx->base + LPI2C_MSR);
return -EAGAIN;
}
if (temp & (MSR_BBF | MSR_MBF))
break;
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
return -ETIMEDOUT;
}
schedule();
}
return 0;
}
static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int bitrate = lpi2c_imx->bitrate;
enum lpi2c_imx_mode mode;
if (bitrate < STARDARD_MAX_BITRATE)
mode = STANDARD;
else if (bitrate < FAST_MAX_BITRATE)
mode = FAST;
else if (bitrate < FAST_PLUS_MAX_BITRATE)
mode = FAST_PLUS;
else if (bitrate < HIGHSPEED_MAX_BITRATE)
mode = HS;
else
mode = ULTRA_FAST;
lpi2c_imx->mode = mode;
}
static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
unsigned int temp;
u8 read;
temp = readl(lpi2c_imx->base + LPI2C_MCR);
temp |= MCR_RRF | MCR_RTF;
writel(temp, lpi2c_imx->base + LPI2C_MCR);
writel(0x7f00, lpi2c_imx->base + LPI2C_MSR);
read = msgs->flags & I2C_M_RD;
temp = (msgs->addr << 1 | read) | (GEN_START << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
return lpi2c_imx_bus_busy(lpi2c_imx);
}
static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned long orig_jiffies = jiffies;
unsigned int temp;
writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
do {
temp = readl(lpi2c_imx->base + LPI2C_MSR);
if (temp & MSR_SDF)
break;
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
break;
}
schedule();
} while (1);
}
/* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
{
u8 prescale, filt, sethold, clkhi, clklo, datavd;
unsigned int clk_rate, clk_cycle;
enum lpi2c_imx_pincfg pincfg;
unsigned int temp;
lpi2c_imx_set_mode(lpi2c_imx);
clk_rate = clk_get_rate(lpi2c_imx->clk);
if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
filt = 0;
else
filt = 2;
for (prescale = 0; prescale <= 7; prescale++) {
clk_cycle = clk_rate / ((1 << prescale) * lpi2c_imx->bitrate)
- 3 - (filt >> 1);
clkhi = (clk_cycle + I2C_CLK_RATIO) / (I2C_CLK_RATIO + 1);
clklo = clk_cycle - clkhi;
if (clklo < 64)
break;
}
if (prescale > 7)
return -EINVAL;
/* set MCFGR1: PINCFG, PRESCALE, IGNACK */
if (lpi2c_imx->mode == ULTRA_FAST)
pincfg = TWO_PIN_OO;
else
pincfg = TWO_PIN_OD;
temp = prescale | pincfg << 24;
if (lpi2c_imx->mode == ULTRA_FAST)
temp |= MCFGR1_IGNACK;
writel(temp, lpi2c_imx->base + LPI2C_MCFGR1);
/* set MCFGR2: FILTSDA, FILTSCL */
temp = (filt << 16) | (filt << 24);
writel(temp, lpi2c_imx->base + LPI2C_MCFGR2);
/* set MCCR: DATAVD, SETHOLD, CLKHI, CLKLO */
sethold = clkhi;
datavd = clkhi >> 1;
temp = datavd << 24 | sethold << 16 | clkhi << 8 | clklo;
if (lpi2c_imx->mode == HS)
writel(temp, lpi2c_imx->base + LPI2C_MCCR1);
else
writel(temp, lpi2c_imx->base + LPI2C_MCCR0);
return 0;
}
static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int temp;
int ret;
ret = clk_enable(lpi2c_imx->clk);
if (ret)
return ret;
temp = MCR_RST;
writel(temp, lpi2c_imx->base + LPI2C_MCR);
writel(0, lpi2c_imx->base + LPI2C_MCR);
ret = lpi2c_imx_config(lpi2c_imx);
if (ret)
goto clk_disable;
temp = readl(lpi2c_imx->base + LPI2C_MCR);
temp |= MCR_MEN;
writel(temp, lpi2c_imx->base + LPI2C_MCR);
return 0;
clk_disable:
clk_disable(lpi2c_imx->clk);
return ret;
}
static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
{
u32 temp;
temp = readl(lpi2c_imx->base + LPI2C_MCR);
temp &= ~MCR_MEN;
writel(temp, lpi2c_imx->base + LPI2C_MCR);
clk_disable(lpi2c_imx->clk);
return 0;
}
static int lpi2c_imx_msg_complete(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned long timeout;
timeout = wait_for_completion_timeout(&lpi2c_imx->complete, HZ);
return timeout ? 0 : -ETIMEDOUT;
}
static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned long orig_jiffies = jiffies;
u32 txcnt;
do {
txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) {
dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n");
return -EIO;
}
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
return -ETIMEDOUT;
}
schedule();
} while (txcnt);
return 0;
}
static void lpi2c_imx_set_tx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
{
writel(lpi2c_imx->txfifosize >> 1, lpi2c_imx->base + LPI2C_MFCR);
}
static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int temp, remaining;
remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
if (remaining > (lpi2c_imx->rxfifosize >> 1))
temp = lpi2c_imx->rxfifosize >> 1;
else
temp = 0;
writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR);
}
static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int data, txcnt;
txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
while (txcnt < lpi2c_imx->txfifosize) {
if (lpi2c_imx->delivered == lpi2c_imx->msglen)
break;
data = lpi2c_imx->tx_buf[lpi2c_imx->delivered++];
writel(data, lpi2c_imx->base + LPI2C_MTDR);
txcnt++;
}
if (lpi2c_imx->delivered < lpi2c_imx->msglen)
lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE);
else
complete(&lpi2c_imx->complete);
}
static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int blocklen, remaining;
unsigned int temp, data;
do {
data = readl(lpi2c_imx->base + LPI2C_MRDR);
if (data & MRDR_RXEMPTY)
break;
lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff;
} while (1);
/*
* First byte is the length of remaining packet in the SMBus block
* data read. Add it to msgs->len.
*/
if (lpi2c_imx->block_data) {
blocklen = lpi2c_imx->rx_buf[0];
lpi2c_imx->msglen += blocklen;
}
remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
if (!remaining) {
complete(&lpi2c_imx->complete);
return;
}
/* not finished, still waiting for rx data */
lpi2c_imx_set_rx_watermark(lpi2c_imx);
/* multiple receive commands */
if (lpi2c_imx->block_data) {
lpi2c_imx->block_data = 0;
temp = remaining;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
} else if (!(lpi2c_imx->delivered & 0xff)) {
temp = (remaining > CHUNK_DATA ? CHUNK_DATA : remaining) - 1;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
}
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE);
}
static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
lpi2c_imx->tx_buf = msgs->buf;
lpi2c_imx_set_tx_watermark(lpi2c_imx);
lpi2c_imx_write_txfifo(lpi2c_imx);
}
static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
unsigned int temp;
lpi2c_imx->rx_buf = msgs->buf;
lpi2c_imx->block_data = msgs->flags & I2C_M_RECV_LEN;
lpi2c_imx_set_rx_watermark(lpi2c_imx);
temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
}
static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(adapter);
unsigned int temp;
int i, result;
result = lpi2c_imx_master_enable(lpi2c_imx);
if (result)
return result;
for (i = 0; i < num; i++) {
result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
if (result)
goto disable;
/* quick smbus */
if (num == 1 && msgs[0].len == 0)
goto stop;
lpi2c_imx->delivered = 0;
lpi2c_imx->msglen = msgs[i].len;
init_completion(&lpi2c_imx->complete);
if (msgs[i].flags & I2C_M_RD)
lpi2c_imx_read(lpi2c_imx, &msgs[i]);
else
lpi2c_imx_write(lpi2c_imx, &msgs[i]);
result = lpi2c_imx_msg_complete(lpi2c_imx);
if (result)
goto stop;
if (!(msgs[i].flags & I2C_M_RD)) {
result = lpi2c_imx_txfifo_empty(lpi2c_imx);
if (result)
goto stop;
}
}
stop:
lpi2c_imx_stop(lpi2c_imx);
temp = readl(lpi2c_imx->base + LPI2C_MSR);
if ((temp & MSR_NDF) && !result)
result = -EIO;
disable:
lpi2c_imx_master_disable(lpi2c_imx);
dev_dbg(&lpi2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
(result < 0) ? "error" : "success msg",
(result < 0) ? result : num);
return (result < 0) ? result : num;
}
static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_id;
unsigned int temp;
lpi2c_imx_intctrl(lpi2c_imx, 0);
temp = readl(lpi2c_imx->base + LPI2C_MSR);
if (temp & MSR_RDF)
lpi2c_imx_read_rxfifo(lpi2c_imx);
if (temp & MSR_TDF)
lpi2c_imx_write_txfifo(lpi2c_imx);
if (temp & MSR_NDF)
complete(&lpi2c_imx->complete);
return IRQ_HANDLED;
}
static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
static struct i2c_algorithm lpi2c_imx_algo = {
.master_xfer = lpi2c_imx_xfer,
.functionality = lpi2c_imx_func,
};
static const struct of_device_id lpi2c_imx_of_match[] = {
{ .compatible = "fsl,imx7ulp-lpi2c" },
{ .compatible = "fsl,imx8dv-lpi2c" },
{ },
};
MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
static int lpi2c_imx_probe(struct platform_device *pdev)
{
struct lpi2c_imx_struct *lpi2c_imx;
struct resource *res;
unsigned int temp;
int irq, ret;
lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
if (!lpi2c_imx)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
lpi2c_imx->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(lpi2c_imx->base))
return PTR_ERR(lpi2c_imx->base);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "can't get irq number\n");
return irq;
}
lpi2c_imx->adapter.owner = THIS_MODULE;
lpi2c_imx->adapter.algo = &lpi2c_imx_algo;
lpi2c_imx->adapter.dev.parent = &pdev->dev;
lpi2c_imx->adapter.dev.of_node = pdev->dev.of_node;
strlcpy(lpi2c_imx->adapter.name, pdev->name,
sizeof(lpi2c_imx->adapter.name));
lpi2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(lpi2c_imx->clk)) {
dev_err(&pdev->dev, "can't get I2C peripheral clock\n");
return PTR_ERR(lpi2c_imx->clk);
}
ret = of_property_read_u32(pdev->dev.of_node,
"clock-frequency", &lpi2c_imx->bitrate);
if (ret)
lpi2c_imx->bitrate = LPI2C_DEFAULT_RATE;
ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0,
pdev->name, lpi2c_imx);
if (ret) {
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
return ret;
}
i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
platform_set_drvdata(pdev, lpi2c_imx);
ret = clk_prepare_enable(lpi2c_imx->clk);
if (ret) {
dev_err(&pdev->dev, "clk enable failed %d\n", ret);
return ret;
}
temp = readl(lpi2c_imx->base + LPI2C_PARAM);
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
clk_disable(lpi2c_imx->clk);
ret = i2c_add_adapter(&lpi2c_imx->adapter);
if (ret)
goto clk_unprepare;
dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
return 0;
clk_unprepare:
clk_unprepare(lpi2c_imx->clk);
return ret;
}
static int lpi2c_imx_remove(struct platform_device *pdev)
{
struct lpi2c_imx_struct *lpi2c_imx = platform_get_drvdata(pdev);
i2c_del_adapter(&lpi2c_imx->adapter);
clk_unprepare(lpi2c_imx->clk);
return 0;
}
static struct platform_driver lpi2c_imx_driver = {
.probe = lpi2c_imx_probe,
.remove = lpi2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = lpi2c_imx_of_match,
},
};
module_platform_driver(lpi2c_imx_driver);
MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus");
MODULE_LICENSE("GPL");

Some files were not shown because too many files have changed in this diff Show more