Commit b8524959 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull i2c updates from Wolfram Sang:
 "Mostly usual driver updates and improvements.  The changelog should
  give an idea.  Standing out is the i2c-qup driver with lots of new
  capabilities and we also have now an i2c-demuxer.

  I'd especially like to welcome Peter Rosin as the i2c-mux maintainer.
  He has an interesting series for muxes in the queue and agreed to look
  after this part of the subsystem.  Thank you, Peter, and welcome
  again!

  The octeon changes were applied pretty recently before the merge
  window.  I am aware.  They are the first (and relatively simple)
  patches of a larger overhaul to this driver.  In case something goes
  wrong with them, they are easy to fix (or revert).  The advantage I
  see is that they are out of the way, and I can concentrate on the next
  block of patches.  I really would like to apply the overhaul in
  smaller batches to avoid regressions.  And waiting a cycle for the
  introductory patches seemed too much of a delay for me"

* 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (39 commits)
  i2c: octeon: Support I2C_M_RECV_LEN
  i2c: octeon: Cleanup resource allocation code
  i2c: octeon: Cleanup i2c-octeon driver
  MAINTAINERS: add Peter Rosin as i2c mux maintainer
  dt-bindings: i2c: Spelling s/propoerty/property/
  i2c: immediately mark ourselves as registered
  i2c: i801: sort IDs alphabetically
  MAINTAINERS: Mika and me are designated reviewers for I2C DESIGNWARE
  i2c: octeon: Cleanup kerneldoc comments
  i2c: do not use internal data from driver core
  i2c: cadence: Fix the kernel-doc warnings
  i2c: imx: remove extra spaces.
  i2c: rcar: don't open code of_device_get_match_data()
  i2c: qup: Fix fifo handling after adding V2 support
  i2c: xiic: Implement power management
  i2c: piix4: Pre-shift the port number
  i2c: piix4: Always use the same type for port
  i2c: piix4: Support alternative port selection register
  i2c: tegra: don't open code of_device_get_match_data()
  i2c: riic, sh_mobile, rcar: Use ARCH_RENESAS
  ...
parents 5266e5b1 886f6f83
What: /sys/devices/platform/<i2c-demux-name>/cur_master
Date: January 2016
KernelVersion: 4.6
Contact: Wolfram Sang <wsa@the-dreams.de>
Description:
This file selects the active I2C master for a demultiplexed bus.
Write 0 there for the first master, 1 for the second etc. Reading the file will
give you a list with the active master marked. Example from a Renesas Lager
board:
root@Lager:~# cat /sys/devices/platform/i2c@8/cur_master
* 0 - /i2c@9
1 - /i2c@e6520000
2 - /i2c@e6530000
root@Lager:~# echo 2 > /sys/devices/platform/i2c@8/cur_master
root@Lager:~# cat /sys/devices/platform/i2c@8/cur_master
0 - /i2c@9
1 - /i2c@e6520000
* 2 - /i2c@e6530000
Pinctrl-based I2C Bus DeMux
This binding describes an I2C bus demultiplexer that uses pin multiplexing to
route the I2C signals, and represents the pin multiplexing configuration using
the pinctrl device tree bindings. This may be used to select one I2C IP core at
runtime which may have a better feature set for a given task than another I2C
IP core on the SoC. The most simple example is to fall back to GPIO bitbanging
if your current runtime configuration hits an errata of the internal IP core.
+-------------------------------+
| SoC |
| | +-----+ +-----+
| +------------+ | | dev | | dev |
| |I2C IP Core1|--\ | +-----+ +-----+
| +------------+ \-------+ | | |
| |Pinctrl|--|------+--------+
| +------------+ +-------+ |
| |I2C IP Core2|--/ |
| +------------+ |
| |
+-------------------------------+
Required properties:
- compatible: "i2c-demux-pinctrl"
- i2c-parent: List of phandles of I2C masters available for selection. The first
one will be used as default.
- i2c-bus-name: The name of this bus. Also needed as pinctrl-name for the I2C
parents.
Furthermore, I2C mux properties and child nodes. See mux.txt in this directory.
Example:
Here is a snipplet for a bus to be demuxed. It contains various i2c clients for
HDMI, so the bus is named "i2c-hdmi":
i2chdmi: i2c@8 {
compatible = "i2c-demux-pinctrl";
i2c-parent = <&gpioi2c>, <&iic2>, <&i2c2>;
i2c-bus-name = "i2c-hdmi";
#address-cells = <1>;
#size-cells = <0>;
ak4643: sound-codec@12 {
compatible = "asahi-kasei,ak4643";
#sound-dai-cells = <0>;
reg = <0x12>;
};
composite-in@20 {
compatible = "adi,adv7180";
reg = <0x20>;
remote = <&vin1>;
port {
adv7180: endpoint {
bus-width = <8>;
remote-endpoint = <&vin1ep0>;
};
};
};
hdmi@39 {
compatible = "adi,adv7511w";
reg = <0x39>;
interrupt-parent = <&gpio1>;
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
adi,input-depth = <8>;
adi,input-colorspace = "rgb";
adi,input-clock = "1x";
adi,input-style = <1>;
adi,input-justification = "evenly";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
adv7511_in: endpoint {
remote-endpoint = <&du_out_lvds0>;
};
};
port@1 {
reg = <1>;
adv7511_out: endpoint {
remote-endpoint = <&hdmi_con>;
};
};
};
};
};
And for clarification, here are the snipplets for the i2c-parents:
gpioi2c: i2c@9 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "i2c-gpio";
status = "disabled";
gpios = <&gpio5 6 GPIO_ACTIVE_HIGH /* sda */
&gpio5 5 GPIO_ACTIVE_HIGH /* scl */
>;
i2c-gpio,delay-us = <5>;
};
...
&i2c2 {
pinctrl-0 = <&i2c2_pins>;
pinctrl-names = "i2c-hdmi";
clock-frequency = <100000>;
};
...
&iic2 {
pinctrl-0 = <&iic2_pins>;
pinctrl-names = "i2c-hdmi";
clock-frequency = <100000>;
};
Please note:
- pinctrl properties for the parent I2C controllers need a pinctrl state
with the same name as i2c-bus-name, not "default"!
- the i2c masters must have their status "disabled". This driver will
enable them at runtime when needed.
...@@ -11,7 +11,7 @@ Required properties: ...@@ -11,7 +11,7 @@ Required properties:
Optional properties: Optional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz. - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
The absence of the propoerty indicates the default frequency 100 kHz. The absence of the property indicates the default frequency 100 kHz.
- dmas: A list of two dma specifiers, one for each entry in dma-names. - dmas: A list of two dma specifiers, one for each entry in dma-names.
- dma-names: should contain "tx" and "rx". - dma-names: should contain "tx" and "rx".
- scl-gpios: specify the gpio related to SCL pin - scl-gpios: specify the gpio related to SCL pin
......
...@@ -17,7 +17,7 @@ Required properties: ...@@ -17,7 +17,7 @@ Required properties:
Optional properties: Optional properties:
- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this - clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
propoerty indicates the default frequency 100 kHz. property indicates the default frequency 100 kHz.
- clocks: clock specifier. - clocks: clock specifier.
- i2c-scl-falling-time-ns: see i2c.txt - i2c-scl-falling-time-ns: see i2c.txt
......
...@@ -8,7 +8,7 @@ Required properties : ...@@ -8,7 +8,7 @@ Required properties :
Optional properties: Optional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz. - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
The absence of the propoerty indicates the default frequency 100 kHz. The absence of the property indicates the default frequency 100 kHz.
Examples : Examples :
......
...@@ -6,14 +6,17 @@ Required properties: ...@@ -6,14 +6,17 @@ Required properties:
- interrupts : IIC controller unterrupt - interrupts : IIC controller unterrupt
- #address-cells = <1> - #address-cells = <1>
- #size-cells = <0> - #size-cells = <0>
- clocks: Input clock specifier. Refer to common clock bindings.
Optional properties: Optional properties:
- Child nodes conforming to i2c bus binding - Child nodes conforming to i2c bus binding
- clock-names: Input clock name, should be 'pclk'.
Example: Example:
axi_iic_0: i2c@40800000 { axi_iic_0: i2c@40800000 {
compatible = "xlnx,xps-iic-2.00.a"; compatible = "xlnx,xps-iic-2.00.a";
clocks = <&clkc 15>;
interrupts = < 1 2 >; interrupts = < 1 2 >;
reg = < 0x40800000 0x10000 >; reg = < 0x40800000 0x10000 >;
......
...@@ -5270,6 +5270,16 @@ F: include/linux/hyperv.h ...@@ -5270,6 +5270,16 @@ F: include/linux/hyperv.h
F: tools/hv/ F: tools/hv/
F: Documentation/ABI/stable/sysfs-bus-vmbus F: Documentation/ABI/stable/sysfs-bus-vmbus
I2C MUXES
M: Peter Rosin <peda@axentia.se>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/i2c/muxes/
F: Documentation/devicetree/bindings/i2c/i2c-mux*
F: drivers/i2c/i2c-mux.c
F: drivers/i2c/muxes/
F: include/linux/i2c-mux.h
I2C OVER PARALLEL PORT I2C OVER PARALLEL PORT
M: Jean Delvare <jdelvare@suse.com> M: Jean Delvare <jdelvare@suse.com>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
...@@ -9676,9 +9686,9 @@ F: Documentation/devicetree/bindings/net/snps,dwc-qos-ethernet.txt ...@@ -9676,9 +9686,9 @@ F: Documentation/devicetree/bindings/net/snps,dwc-qos-ethernet.txt
F: drivers/net/ethernet/synopsys/dwc_eth_qos.c F: drivers/net/ethernet/synopsys/dwc_eth_qos.c
SYNOPSYS DESIGNWARE I2C DRIVER SYNOPSYS DESIGNWARE I2C DRIVER
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
M: Jarkko Nikula <jarkko.nikula@linux.intel.com> M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
M: Mika Westerberg <mika.westerberg@linux.intel.com> R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
R: Mika Westerberg <mika.westerberg@linux.intel.com>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
S: Maintained S: Maintained
F: drivers/i2c/busses/i2c-designware-* F: drivers/i2c/busses/i2c-designware-*
......
...@@ -789,7 +789,7 @@ config I2C_QUP ...@@ -789,7 +789,7 @@ config I2C_QUP
config I2C_RIIC config I2C_RIIC
tristate "Renesas RIIC adapter" tristate "Renesas RIIC adapter"
depends on ARCH_SHMOBILE || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
Renesas RIIC I2C interface. Renesas RIIC I2C interface.
...@@ -833,7 +833,7 @@ config I2C_SH7760 ...@@ -833,7 +833,7 @@ config I2C_SH7760
config I2C_SH_MOBILE config I2C_SH_MOBILE
tristate "SuperH Mobile I2C Controller" tristate "SuperH Mobile I2C Controller"
depends on HAS_DMA depends on HAS_DMA
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
built-in I2C interface on the Renesas SH-Mobile processor. built-in I2C interface on the Renesas SH-Mobile processor.
...@@ -908,7 +908,7 @@ config I2C_TEGRA ...@@ -908,7 +908,7 @@ config I2C_TEGRA
config I2C_UNIPHIER config I2C_UNIPHIER
tristate "UniPhier FIFO-less I2C controller" tristate "UniPhier FIFO-less I2C controller"
depends on ARCH_UNIPHIER depends on ARCH_UNIPHIER || COMPILE_TEST
help help
If you say yes to this option, support will be included for If you say yes to this option, support will be included for
the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8, the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8,
...@@ -916,7 +916,7 @@ config I2C_UNIPHIER ...@@ -916,7 +916,7 @@ config I2C_UNIPHIER
config I2C_UNIPHIER_F config I2C_UNIPHIER_F
tristate "UniPhier FIFO-builtin I2C controller" tristate "UniPhier FIFO-builtin I2C controller"
depends on ARCH_UNIPHIER depends on ARCH_UNIPHIER || COMPILE_TEST
help help
If you say yes to this option, support will be included for If you say yes to this option, support will be included for
the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4, the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4,
...@@ -985,7 +985,7 @@ config I2C_XLP9XX ...@@ -985,7 +985,7 @@ config I2C_XLP9XX
config I2C_RCAR config I2C_RCAR
tristate "Renesas R-Car I2C Controller" tristate "Renesas R-Car I2C Controller"
depends on ARCH_SHMOBILE || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
select I2C_SLAVE select I2C_SLAVE
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
......
...@@ -58,11 +58,13 @@ ...@@ -58,11 +58,13 @@
#define IE_M_RX_FIFO_FULL_SHIFT 31 #define IE_M_RX_FIFO_FULL_SHIFT 31
#define IE_M_RX_THLD_SHIFT 30 #define IE_M_RX_THLD_SHIFT 30
#define IE_M_START_BUSY_SHIFT 28 #define IE_M_START_BUSY_SHIFT 28
#define IE_M_TX_UNDERRUN_SHIFT 27
#define IS_OFFSET 0x3c #define IS_OFFSET 0x3c
#define IS_M_RX_FIFO_FULL_SHIFT 31 #define IS_M_RX_FIFO_FULL_SHIFT 31
#define IS_M_RX_THLD_SHIFT 30 #define IS_M_RX_THLD_SHIFT 30
#define IS_M_START_BUSY_SHIFT 28 #define IS_M_START_BUSY_SHIFT 28
#define IS_M_TX_UNDERRUN_SHIFT 27
#define M_TX_OFFSET 0x40 #define M_TX_OFFSET 0x40
#define M_TX_WR_STATUS_SHIFT 31 #define M_TX_WR_STATUS_SHIFT 31
...@@ -76,7 +78,7 @@ ...@@ -76,7 +78,7 @@
#define M_RX_DATA_SHIFT 0 #define M_RX_DATA_SHIFT 0
#define M_RX_DATA_MASK 0xff #define M_RX_DATA_MASK 0xff
#define I2C_TIMEOUT_MESC 100 #define I2C_TIMEOUT_MSEC 50000
#define M_TX_RX_FIFO_SIZE 64 #define M_TX_RX_FIFO_SIZE 64
enum bus_speed_index { enum bus_speed_index {
...@@ -95,12 +97,17 @@ struct bcm_iproc_i2c_dev { ...@@ -95,12 +97,17 @@ struct bcm_iproc_i2c_dev {
struct completion done; struct completion done;
int xfer_is_done; int xfer_is_done;
struct i2c_msg *msg;
/* bytes that have been transferred */
unsigned int tx_bytes;
}; };
/* /*
* Can be expanded in the future if more interrupt status bits are utilized * Can be expanded in the future if more interrupt status bits are utilized
*/ */
#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) #define ISR_MASK (BIT(IS_M_START_BUSY_SHIFT) | BIT(IS_M_TX_UNDERRUN_SHIFT))
static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
{ {
...@@ -112,13 +119,95 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) ...@@ -112,13 +119,95 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
if (!status) if (!status)
return IRQ_NONE; return IRQ_NONE;
writel(status, iproc_i2c->base + IS_OFFSET); /* TX FIFO is empty and we have more data to send */
if (status & BIT(IS_M_TX_UNDERRUN_SHIFT)) {
struct i2c_msg *msg = iproc_i2c->msg;
unsigned int tx_bytes = msg->len - iproc_i2c->tx_bytes;
unsigned int i;
u32 val;
/* can only fill up to the FIFO size */
tx_bytes = min_t(unsigned int, tx_bytes, M_TX_RX_FIFO_SIZE);
for (i = 0; i < tx_bytes; i++) {
/* start from where we left over */
unsigned int idx = iproc_i2c->tx_bytes + i;
val = msg->buf[idx];
/* mark the last byte */
if (idx == msg->len - 1) {
u32 tmp;
val |= BIT(M_TX_WR_STATUS_SHIFT);
/*
* Since this is the last byte, we should
* now disable TX FIFO underrun interrupt
*/
tmp = readl(iproc_i2c->base + IE_OFFSET);
tmp &= ~BIT(IE_M_TX_UNDERRUN_SHIFT);
writel(tmp, iproc_i2c->base + IE_OFFSET);
}
/* load data into TX FIFO */
writel(val, iproc_i2c->base + M_TX_OFFSET);
}
/* update number of transferred bytes */
iproc_i2c->tx_bytes += tx_bytes;
}
if (status & BIT(IS_M_START_BUSY_SHIFT)) {
iproc_i2c->xfer_is_done = 1; iproc_i2c->xfer_is_done = 1;
complete_all(&iproc_i2c->done); complete_all(&iproc_i2c->done);
}
writel(status, iproc_i2c->base + IS_OFFSET);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
{
u32 val;
/* put controller in reset */
val = readl(iproc_i2c->base + CFG_OFFSET);
val |= 1 << CFG_RESET_SHIFT;
val &= ~(1 << CFG_EN_SHIFT);
writel(val, iproc_i2c->base + CFG_OFFSET);
/* wait 100 usec per spec */
udelay(100);
/* bring controller out of reset */
val &= ~(1 << CFG_RESET_SHIFT);
writel(val, iproc_i2c->base + CFG_OFFSET);
/* flush TX/RX FIFOs and set RX FIFO threshold to zero */
val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
/* disable all interrupts */
writel(0, iproc_i2c->base + IE_OFFSET);
/* clear all pending interrupts */
writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
return 0;
}
static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
bool enable)
{
u32 val;
val = readl(iproc_i2c->base + CFG_OFFSET);
if (enable)
val |= BIT(CFG_EN_SHIFT);
else
val &= ~BIT(CFG_EN_SHIFT);
writel(val, iproc_i2c->base + CFG_OFFSET);
}
static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c, static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
struct i2c_msg *msg) struct i2c_msg *msg)
{ {
...@@ -149,6 +238,12 @@ static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c, ...@@ -149,6 +238,12 @@ static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
default: default:
dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val); dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
/* re-initialize i2c for recovery */
bcm_iproc_i2c_enable_disable(iproc_i2c, false);
bcm_iproc_i2c_init(iproc_i2c);
bcm_iproc_i2c_enable_disable(iproc_i2c, true);
return -EIO; return -EIO;
} }
} }
...@@ -159,7 +254,8 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, ...@@ -159,7 +254,8 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
int ret, i; int ret, i;
u8 addr; u8 addr;
u32 val; u32 val;
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC); unsigned int tx_bytes;
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MSEC);
/* check if bus is busy */ /* check if bus is busy */
if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) & if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
...@@ -168,13 +264,20 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, ...@@ -168,13 +264,20 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
return -EBUSY; return -EBUSY;
} }
iproc_i2c->msg = msg;
/* format and load slave address into the TX FIFO */ /* format and load slave address into the TX FIFO */
addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0); addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
writel(addr, iproc_i2c->base + M_TX_OFFSET); writel(addr, iproc_i2c->base + M_TX_OFFSET);
/* for a write transaction, load data into the TX FIFO */ /*
* For a write transaction, load data into the TX FIFO. Only allow
* loading up to TX FIFO size - 1 bytes of data since the first byte
* has been used up by the slave address
*/
tx_bytes = min_t(unsigned int, msg->len, M_TX_RX_FIFO_SIZE - 1);
if (!(msg->flags & I2C_M_RD)) { if (!(msg->flags & I2C_M_RD)) {
for (i = 0; i < msg->len; i++) { for (i = 0; i < tx_bytes; i++) {
val = msg->buf[i]; val = msg->buf[i];
/* mark the last byte */ /* mark the last byte */
...@@ -183,6 +286,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, ...@@ -183,6 +286,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
writel(val, iproc_i2c->base + M_TX_OFFSET); writel(val, iproc_i2c->base + M_TX_OFFSET);
} }
iproc_i2c->tx_bytes = tx_bytes;
} }
/* mark as incomplete before starting the transaction */ /* mark as incomplete before starting the transaction */
...@@ -194,13 +298,24 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, ...@@ -194,13 +298,24 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
* transaction is done, i.e., the internal start_busy bit, transitions * transaction is done, i.e., the internal start_busy bit, transitions
* from 1 to 0. * from 1 to 0.
*/ */
writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET); val = BIT(IE_M_START_BUSY_SHIFT);
/*
* If TX data size is larger than the TX FIFO, need to enable TX
* underrun interrupt, which will be triggerred when the TX FIFO is
* empty. When that happens we can then pump more data into the FIFO
*/
if (!(msg->flags & I2C_M_RD) &&
msg->len > iproc_i2c->tx_bytes)
val |= BIT(IE_M_TX_UNDERRUN_SHIFT);
writel(val, iproc_i2c->base + IE_OFFSET);
/* /*
* Now we can activate the transfer. For a read operation, specify the * Now we can activate the transfer. For a read operation, specify the
* number of bytes to read * number of bytes to read
*/ */
val = 1 << M_CMD_START_BUSY_SHIFT; val = BIT(M_CMD_START_BUSY_SHIFT);
if (msg->flags & I2C_M_RD) { if (msg->flags & I2C_M_RD) {
val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) | val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
(msg->len << M_CMD_RD_CNT_SHIFT); (msg->len << M_CMD_RD_CNT_SHIFT);
...@@ -283,7 +398,6 @@ static const struct i2c_algorithm bcm_iproc_algo = { ...@@ -283,7 +398,6 @@ static const struct i2c_algorithm bcm_iproc_algo = {
static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
/* need to reserve one byte in the FIFO for the slave address */ /* need to reserve one byte in the FIFO for the slave address */
.max_read_len = M_TX_RX_FIFO_SIZE - 1, .max_read_len = M_TX_RX_FIFO_SIZE - 1,
.max_write_len = M_TX_RX_FIFO_SIZE - 1,
}; };
static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
...@@ -321,49 +435,6 @@ static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) ...@@ -321,49 +435,6 @@ static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
return 0; return 0;
} }
static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
{
u32 val;
/* put controller in reset */
val = readl(iproc_i2c->base + CFG_OFFSET);
val |= 1 << CFG_RESET_SHIFT;
val &= ~(1 << CFG_EN_SHIFT);
writel(val, iproc_i2c->base + CFG_OFFSET);
/* wait 100 usec per spec */
udelay(100);
/* bring controller out of reset */
val &= ~(1 << CFG_RESET_SHIFT);
writel(val, iproc_i2c->base + CFG_OFFSET);
/* flush TX/RX FIFOs and set RX FIFO threshold to zero */
val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
/* disable all interrupts */
writel(0, iproc_i2c->base + IE_OFFSET);
/* clear all pending interrupts */
writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
return 0;
}
static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
bool enable)
{
u32 val;
val = readl(iproc_i2c->base + CFG_OFFSET);
if (enable)
val |= BIT(CFG_EN_SHIFT);
else
val &= ~BIT(CFG_EN_SHIFT);
writel(val, iproc_i2c->base + CFG_OFFSET);
}
static int bcm_iproc_i2c_probe(struct platform_device *pdev) static int bcm_iproc_i2c_probe(struct platform_device *pdev)
{ {
int irq, ret = 0; int irq, ret = 0;
......
...@@ -124,6 +124,8 @@ ...@@ -124,6 +124,8 @@
/** /**
* struct cdns_i2c - I2C device private data structure * struct cdns_i2c - I2C device private data structure
*
* @dev: Pointer to device structure
* @membase: Base address of the I2C device * @membase: Base address of the I2C device
* @adap: I2C adapter instance * @adap: I2C adapter instance
* @p_msg: Message pointer * @p_msg: Message pointer
...@@ -171,7 +173,7 @@ struct cdns_platform_data { ...@@ -171,7 +173,7 @@ struct cdns_platform_data {
clk_rate_change_nb) clk_rate_change_nb)
/** /**
* cdns_i2c_clear_bus_hold() - Clear bus hold bit * cdns_i2c_clear_bus_hold - Clear bus hold bit
* @id: Pointer to driver data struct * @id: Pointer to driver data struct
* *
* Helper to clear the controller's bus hold bit. * Helper to clear the controller's bus hold bit.
...@@ -815,8 +817,8 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long ...@@ -815,8 +817,8 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
} }
/** /**
* cdns_i2c_suspend - Suspend method for the driver * cdns_i2c_runtime_suspend - Runtime suspend method for the driver
* @_dev: Address of the platform_device structure * @dev: Address of the platform_device structure
* *
* Put the driver into low power mode. * Put the driver into low power mode.
* *
...@@ -833,10 +835,10 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) ...@@ -833,10 +835,10 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
} }
/** /**
* cdns_i2c_resume - Resume from suspend * cdns_i2c_runtime_resume - Runtime resume
* @_dev: Address of the platform_device structure * @dev: Address of the platform_device structure
* *
* Resume operation after suspend. * Runtime resume callback.
* *
* Return: 0 on success and error value on error * Return: 0 on success and error value on error
*/ */
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details. * more details.
*/ */
#include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
...@@ -151,7 +150,3 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) ...@@ -151,7 +150,3 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
return 0; return 0;
} }
MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
MODULE_LICENSE("GPL v2");
...@@ -634,7 +634,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -634,7 +634,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
mutex_lock(&dev->lock);
pm_runtime_get_sync(dev->dev); pm_runtime_get_sync(dev->dev);
reinit_completion(&dev->cmd_complete); reinit_completion(&dev->cmd_complete);
...@@ -673,11 +672,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -673,11 +672,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
} }
/* /*
* We must disable the adapter before unlocking the &dev->lock mutex * We must disable the adapter before returning and signaling the end
* below. Otherwise the hardware might continue generating interrupts * of the current transfer. Otherwise the hardware might continue
* which in turn causes a race condition with the following transfer. * generating interrupts which in turn causes a race condition with
* Needs some more investigation if the additional interrupts are * the following transfer. Needs some more investigation if the
* a hardware bug or this driver doesn't handle them correctly yet. * additional interrupts are a hardware bug or this driver doesn't
* handle them correctly yet.
*/ */
__i2c_dw_enable(dev, false); __i2c_dw_enable(dev, false);
...@@ -706,7 +706,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -706,7 +706,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
done_nolock: done_nolock:
pm_runtime_mark_last_busy(dev->dev); pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev); pm_runtime_put_autosuspend(dev->dev);
mutex_unlock(&dev->lock);
return ret; return ret;
} }
...@@ -860,7 +859,6 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) ...@@ -860,7 +859,6 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
int r; int r;
init_completion(&dev->cmd_complete); init_completion(&dev->cmd_complete);
mutex_init(&dev->lock);
r = i2c_dw_init(dev); r = i2c_dw_init(dev);
if (r) if (r)
...@@ -883,9 +881,17 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) ...@@ -883,9 +881,17 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
return r; return r;
} }
/*
* Increment PM usage count during adapter registration in order to
* avoid possible spurious runtime suspend when adapter device is
* registered to the device core and immediate resume in case bus has
* registered I2C slaves that do I2C transfers in their probe.
*/
pm_runtime_get_noresume(dev->dev);
r = i2c_add_numbered_adapter(adap); r = i2c_add_numbered_adapter(adap);
if (r) if (r)
dev_err(dev->dev, "failure adding adapter: %d\n", r); dev_err(dev->dev, "failure adding adapter: %d\n", r);
pm_runtime_put_noidle(dev->dev);
return r; return r;
} }
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
* @dev: driver model device node * @dev: driver model device node
* @base: IO registers pointer * @base: IO registers pointer
* @cmd_complete: tx completion indicator * @cmd_complete: tx completion indicator
* @lock: protect this struct and IO registers
* @clk: input reference clock * @clk: input reference clock
* @cmd_err: run time hadware error code * @cmd_err: run time hadware error code
* @msgs: points to an array of messages currently being transfered * @msgs: points to an array of messages currently being transfered
...@@ -73,7 +72,6 @@ struct dw_i2c_dev { ...@@ -73,7 +72,6 @@ struct dw_i2c_dev {
struct device *dev; struct device *dev;
void __iomem *base; void __iomem *base;
struct completion cmd_complete; struct completion cmd_complete;
struct mutex lock;
struct clk *clk; struct clk *clk;
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev); u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
struct dw_pci_controller *controller; struct dw_pci_controller *controller;
......
...@@ -184,7 +184,7 @@ ...@@ -184,7 +184,7 @@
/* Older devices have their ID defined in <linux/pci_ids.h> */ /* Older devices have their ID defined in <linux/pci_ids.h> */
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292 #define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
/* Patsburg also has three 'Integrated Device Function' SMBus controllers */ /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
...@@ -193,9 +193,11 @@ ...@@ -193,9 +193,11 @@
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c #define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c
#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
...@@ -204,10 +206,8 @@ ...@@ -204,10 +206,8 @@
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23
#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#define I2C_DMA_INT_FLAG_NONE 0x0000 #define I2C_DMA_INT_FLAG_NONE 0x0000
#define I2C_DMA_CLR_FLAG 0x0000 #define I2C_DMA_CLR_FLAG 0x0000
#define I2C_DMA_HARD_RST 0x0002 #define I2C_DMA_HARD_RST 0x0002
#define I2C_DMA_4G_MODE 0x0001
#define I2C_DEFAULT_SPEED 100000 /* hz */ #define I2C_DEFAULT_SPEED 100000 /* hz */
#define MAX_FS_MODE_SPEED 400000 #define MAX_FS_MODE_SPEED 400000
...@@ -88,6 +89,8 @@ enum DMA_REGS_OFFSET { ...@@ -88,6 +89,8 @@ enum DMA_REGS_OFFSET {
OFFSET_RX_MEM_ADDR = 0x20, OFFSET_RX_MEM_ADDR = 0x20,
OFFSET_TX_LEN = 0x24, OFFSET_TX_LEN = 0x24,
OFFSET_RX_LEN = 0x28, OFFSET_RX_LEN = 0x28,
OFFSET_TX_4G_MODE = 0x54,
OFFSET_RX_4G_MODE = 0x58,
}; };
enum i2c_trans_st_rs { enum i2c_trans_st_rs {
...@@ -133,6 +136,7 @@ struct mtk_i2c_compatible { ...@@ -133,6 +136,7 @@ struct mtk_i2c_compatible {
unsigned char dcm: 1; unsigned char dcm: 1;
unsigned char auto_restart: 1; unsigned char auto_restart: 1;
unsigned char aux_len_reg: 1; unsigned char aux_len_reg: 1;
unsigned char support_33bits: 1;
}; };
struct mtk_i2c { struct mtk_i2c {
...@@ -182,6 +186,7 @@ static const struct mtk_i2c_compatible mt6577_compat = { ...@@ -182,6 +186,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
.dcm = 1, .dcm = 1,
.auto_restart = 0, .auto_restart = 0,
.aux_len_reg = 0, .aux_len_reg = 0,
.support_33bits = 0,
}; };
static const struct mtk_i2c_compatible mt6589_compat = { static const struct mtk_i2c_compatible mt6589_compat = {
...@@ -190,6 +195,7 @@ static const struct mtk_i2c_compatible mt6589_compat = { ...@@ -190,6 +195,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
.dcm = 0, .dcm = 0,
.auto_restart = 0, .auto_restart = 0,
.aux_len_reg = 0, .aux_len_reg = 0,
.support_33bits = 0,
}; };
static const struct mtk_i2c_compatible mt8173_compat = { static const struct mtk_i2c_compatible mt8173_compat = {
...@@ -198,6 +204,7 @@ static const struct mtk_i2c_compatible mt8173_compat = { ...@@ -198,6 +204,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
.dcm = 1, .dcm = 1,
.auto_restart = 1, .auto_restart = 1,
.aux_len_reg = 1, .aux_len_reg = 1,
.support_33bits = 1,
}; };
static const struct of_device_id mtk_i2c_of_match[] = { static const struct of_device_id mtk_i2c_of_match[] = {
...@@ -366,6 +373,11 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk, ...@@ -366,6 +373,11 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
return 0; return 0;
} }
static inline u32 mtk_i2c_set_4g_mode(dma_addr_t addr)
{
return (addr & BIT_ULL(32)) ? I2C_DMA_4G_MODE : I2C_DMA_CLR_FLAG;
}
static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
int num, int left_num) int num, int left_num)
{ {
...@@ -373,6 +385,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -373,6 +385,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
u16 start_reg; u16 start_reg;
u16 control_reg; u16 control_reg;
u16 restart_flag = 0; u16 restart_flag = 0;
u32 reg_4g_mode;
dma_addr_t rpaddr = 0; dma_addr_t rpaddr = 0;
dma_addr_t wpaddr = 0; dma_addr_t wpaddr = 0;
int ret; int ret;
...@@ -439,6 +452,12 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -439,6 +452,12 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
msgs->len, DMA_FROM_DEVICE); msgs->len, DMA_FROM_DEVICE);
if (dma_mapping_error(i2c->dev, rpaddr)) if (dma_mapping_error(i2c->dev, rpaddr))
return -ENOMEM; return -ENOMEM;
if (i2c->dev_comp->support_33bits) {
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
}
writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR); writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR);
writel(msgs->len, i2c->pdmabase + OFFSET_RX_LEN); writel(msgs->len, i2c->pdmabase + OFFSET_RX_LEN);
} else if (i2c->op == I2C_MASTER_WR) { } else if (i2c->op == I2C_MASTER_WR) {
...@@ -448,6 +467,12 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -448,6 +467,12 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
msgs->len, DMA_TO_DEVICE); msgs->len, DMA_TO_DEVICE);
if (dma_mapping_error(i2c->dev, wpaddr)) if (dma_mapping_error(i2c->dev, wpaddr))
return -ENOMEM; return -ENOMEM;
if (i2c->dev_comp->support_33bits) {
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
}
writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR); writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR);
writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN); writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN);
} else { } else {
...@@ -465,6 +490,15 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -465,6 +490,15 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
msgs->len, DMA_TO_DEVICE); msgs->len, DMA_TO_DEVICE);
return -ENOMEM; return -ENOMEM;
} }
if (i2c->dev_comp->support_33bits) {
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
}
writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR); writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR);
writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR); writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR);
writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN); writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN);
...@@ -729,6 +763,14 @@ static int mtk_i2c_probe(struct platform_device *pdev) ...@@ -729,6 +763,14 @@ static int mtk_i2c_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
if (i2c->dev_comp->support_33bits) {
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(33));
if (ret) {
dev_err(&pdev->dev, "dma_set_mask return error.\n");
return ret;
}
}
ret = mtk_i2c_clock_enable(i2c); ret = mtk_i2c_clock_enable(i2c);
if (ret) { if (ret) {
dev_err(&pdev->dev, "clock enable failed!\n"); dev_err(&pdev->dev, "clock enable failed!\n");
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* (C) Copyright 2009-2010 * (C) Copyright 2009-2010
* Nokia Siemens Networks, michael.lawnick.ext@nsn.com * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
* *
* Portions Copyright (C) 2010, 2011 Cavium Networks, Inc. * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
* *
* This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
* *
...@@ -26,30 +26,34 @@ ...@@ -26,30 +26,34 @@
#define DRV_NAME "i2c-octeon" #define DRV_NAME "i2c-octeon"
/* The previous out-of-tree version was implicitly version 1.0. */ /* Register offsets */
#define DRV_VERSION "2.0"
/* register offsets */
#define SW_TWSI 0x00 #define SW_TWSI 0x00
#define TWSI_INT 0x10 #define TWSI_INT 0x10
/* Controller command patterns */ /* Controller command patterns */
#define SW_TWSI_V 0x8000000000000000ull #define SW_TWSI_V BIT_ULL(63) /* Valid bit */
#define SW_TWSI_EOP_TWSI_DATA 0x0C00000100000000ull #define SW_TWSI_R BIT_ULL(56) /* Result or read bit */
#define SW_TWSI_EOP_TWSI_CTL 0x0C00000200000000ull
#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C00000300000000ull /* Controller opcode word (bits 60:57) */
#define SW_TWSI_EOP_TWSI_STAT 0x0C00000300000000ull #define SW_TWSI_OP_SHIFT 57
#define SW_TWSI_EOP_TWSI_RST 0x0C00000700000000ull #define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT)
#define SW_TWSI_OP_TWSI_CLK 0x0800000000000000ull #define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
#define SW_TWSI_R 0x0100000000000000ull
/* Controller extended opcode word (bits 34:32) */
#define SW_TWSI_EOP_SHIFT 32
#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT)
#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT)
#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
/* Controller command and status bits */ /* Controller command and status bits */
#define TWSI_CTL_CE 0x80 #define TWSI_CTL_CE 0x80
#define TWSI_CTL_ENAB 0x40 #define TWSI_CTL_ENAB 0x40 /* Bus enable */
#define TWSI_CTL_STA 0x20 #define TWSI_CTL_STA 0x20 /* Master-mode start, HW clears when done */
#define TWSI_CTL_STP 0x10 #define TWSI_CTL_STP 0x10 /* Master-mode stop, HW clears when done */
#define TWSI_CTL_IFLG 0x08 #define TWSI_CTL_IFLG 0x08 /* HW event, SW writes 0 to ACK */
#define TWSI_CTL_AAK 0x04 #define TWSI_CTL_AAK 0x04 /* Assert ACK */
/* Some status values */ /* Some status values */
#define STAT_START 0x08 #define STAT_START 0x08
...@@ -60,29 +64,30 @@ ...@@ -60,29 +64,30 @@
#define STAT_RXDATA_ACK 0x50 #define STAT_RXDATA_ACK 0x50
#define STAT_IDLE 0xF8 #define STAT_IDLE 0xF8
/* TWSI_INT values */
#define TWSI_INT_CORE_EN BIT_ULL(6)
#define TWSI_INT_SDA_OVR BIT_ULL(8)
#define TWSI_INT_SCL_OVR BIT_ULL(9)
struct octeon_i2c { struct octeon_i2c {
wait_queue_head_t queue; wait_queue_head_t queue;
struct i2c_adapter adap; struct i2c_adapter adap;
int irq; int irq;
u32 twsi_freq; u32 twsi_freq;
int sys_freq; int sys_freq;
resource_size_t twsi_phys;
void __iomem *twsi_base; void __iomem *twsi_base;
resource_size_t regsize;
struct device *dev; struct device *dev;
}; };
/** /**
* octeon_i2c_write_sw - write an I2C core register. * octeon_i2c_write_sw - write an I2C core register
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* @eop_reg: Register selector. * @eop_reg: Register selector
* @data: Value to be written. * @data: Value to be written
* *
* The I2C core registers are accessed indirectly via the SW_TWSI CSR. * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
*/ */
static void octeon_i2c_write_sw(struct octeon_i2c *i2c, static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
u64 eop_reg,
u8 data)
{ {
u64 tmp; u64 tmp;
...@@ -93,9 +98,9 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c, ...@@ -93,9 +98,9 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c,
} }
/** /**
* octeon_i2c_read_sw - write an I2C core register. * octeon_i2c_read_sw - read lower bits of an I2C core register
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* @eop_reg: Register selector. * @eop_reg: Register selector
* *
* Returns the data. * Returns the data.
* *
...@@ -115,8 +120,8 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg) ...@@ -115,8 +120,8 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
/** /**
* octeon_i2c_write_int - write the TWSI_INT register * octeon_i2c_write_int - write the TWSI_INT register
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* @data: Value to be written. * @data: Value to be written
*/ */
static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
{ {
...@@ -125,57 +130,52 @@ static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) ...@@ -125,57 +130,52 @@ static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
} }
/** /**
* octeon_i2c_int_enable - enable the TS interrupt. * octeon_i2c_int_enable - enable the CORE interrupt
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* *
* The interrupt will be asserted when there is non-STAT_IDLE state in * The interrupt will be asserted when there is non-STAT_IDLE state in
* the SW_TWSI_EOP_TWSI_STAT register. * the SW_TWSI_EOP_TWSI_STAT register.
*/ */
static void octeon_i2c_int_enable(struct octeon_i2c *i2c) static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
{ {
octeon_i2c_write_int(i2c, 0x40); octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN);
} }
/** /* disable the CORE interrupt */
* octeon_i2c_int_disable - disable the TS interrupt.
* @i2c: The struct octeon_i2c.
*/
static void octeon_i2c_int_disable(struct octeon_i2c *i2c) static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
{ {
/* clear TS/ST/IFLG events */
octeon_i2c_write_int(i2c, 0); octeon_i2c_write_int(i2c, 0);
} }
/** /**
* octeon_i2c_unblock - unblock the bus. * octeon_i2c_unblock - unblock the bus
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* *
* If there was a reset while a device was driving 0 to bus, * If there was a reset while a device was driving 0 to bus, bus is blocked.
* bus is blocked. We toggle it free manually by some clock * We toggle it free manually by some clock cycles and send a stop.
* cycles and send a stop.
*/ */
static void octeon_i2c_unblock(struct octeon_i2c *i2c) static void octeon_i2c_unblock(struct octeon_i2c *i2c)
{ {
int i; int i;
dev_dbg(i2c->dev, "%s\n", __func__); dev_dbg(i2c->dev, "%s\n", __func__);
for (i = 0; i < 9; i++) { for (i = 0; i < 9; i++) {
octeon_i2c_write_int(i2c, 0x0); octeon_i2c_write_int(i2c, 0);
udelay(5); udelay(5);
octeon_i2c_write_int(i2c, 0x200); octeon_i2c_write_int(i2c, TWSI_INT_SCL_OVR);
udelay(5); udelay(5);
} }
octeon_i2c_write_int(i2c, 0x300); /* hand-crank a STOP */
octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR);
udelay(5); udelay(5);
octeon_i2c_write_int(i2c, 0x100); octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR);
udelay(5); udelay(5);
octeon_i2c_write_int(i2c, 0x0); octeon_i2c_write_int(i2c, 0);
} }
/** /* interrupt service routine */
* octeon_i2c_isr - the interrupt service routine.
* @int: The irq, unused.
* @dev_id: Our struct octeon_i2c.
*/
static irqreturn_t octeon_i2c_isr(int irq, void *dev_id) static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
{ {
struct octeon_i2c *i2c = dev_id; struct octeon_i2c *i2c = dev_id;
...@@ -193,24 +193,20 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c) ...@@ -193,24 +193,20 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
} }
/** /**
* octeon_i2c_wait - wait for the IFLG to be set. * octeon_i2c_wait - wait for the IFLG to be set
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* *
* Returns 0 on success, otherwise a negative errno. * Returns 0 on success, otherwise a negative errno.
*/ */
static int octeon_i2c_wait(struct octeon_i2c *i2c) static int octeon_i2c_wait(struct octeon_i2c *i2c)
{ {
long result; long time_left;
octeon_i2c_int_enable(i2c); octeon_i2c_int_enable(i2c);
time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
result = wait_event_timeout(i2c->queue,
octeon_i2c_test_iflg(i2c),
i2c->adap.timeout); i2c->adap.timeout);
octeon_i2c_int_disable(i2c); octeon_i2c_int_disable(i2c);
if (!time_left) {
if (result == 0) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__); dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -219,15 +215,15 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) ...@@ -219,15 +215,15 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
} }
/** /**
* octeon_i2c_start - send START to the bus. * octeon_i2c_start - send START to the bus
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* *
* Returns 0 on success, otherwise a negative errno. * Returns 0 on success, otherwise a negative errno.
*/ */
static int octeon_i2c_start(struct octeon_i2c *i2c) static int octeon_i2c_start(struct octeon_i2c *i2c)
{ {
u8 data;
int result; int result;
u8 data;
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB | TWSI_CTL_STA); TWSI_CTL_ENAB | TWSI_CTL_STA);
...@@ -243,7 +239,6 @@ static int octeon_i2c_start(struct octeon_i2c *i2c) ...@@ -243,7 +239,6 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
octeon_i2c_unblock(i2c); octeon_i2c_unblock(i2c);
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB | TWSI_CTL_STA); TWSI_CTL_ENAB | TWSI_CTL_STA);
result = octeon_i2c_wait(i2c); result = octeon_i2c_wait(i2c);
} }
if (result) if (result)
...@@ -259,34 +254,19 @@ static int octeon_i2c_start(struct octeon_i2c *i2c) ...@@ -259,34 +254,19 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
return 0; return 0;
} }
/** /* send STOP to the bus */
* octeon_i2c_stop - send STOP to the bus. static void octeon_i2c_stop(struct octeon_i2c *i2c)
* @i2c: The struct octeon_i2c.
*
* Returns 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_stop(struct octeon_i2c *i2c)
{ {
u8 data;
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB | TWSI_CTL_STP); TWSI_CTL_ENAB | TWSI_CTL_STP);
data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
if (data != STAT_IDLE) {
dev_err(i2c->dev, "%s: bad status(0x%x)\n", __func__, data);
return -EIO;
}
return 0;
} }
/** /**
* octeon_i2c_write - send data to the bus. * octeon_i2c_write - send data to the bus via low-level controller
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* @target: Target address. * @target: Target address
* @data: Pointer to the data to be sent. * @data: Pointer to the data to be sent
* @length: Length of the data. * @length: Length of the data
* *
* The address is sent over the bus, then the data. * The address is sent over the bus, then the data.
* *
...@@ -311,6 +291,7 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int target, ...@@ -311,6 +291,7 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) { if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) {
dev_err(i2c->dev, dev_err(i2c->dev,
"%s: bad status before write (0x%x)\n", "%s: bad status before write (0x%x)\n",
...@@ -330,20 +311,21 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int target, ...@@ -330,20 +311,21 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
} }
/** /**
* octeon_i2c_read - receive data from the bus. * octeon_i2c_read - receive data from the bus via low-level controller
* @i2c: The struct octeon_i2c. * @i2c: The struct octeon_i2c
* @target: Target address. * @target: Target address
* @data: Pointer to the location to store the datae . * @data: Pointer to the location to store the data
* @length: Length of the data. * @rlength: Length of the data
* @recv_len: flag for length byte
* *
* The address is sent over the bus, then the data is read. * The address is sent over the bus, then the data is read.
* *
* Returns 0 on success, otherwise a negative errno. * Returns 0 on success, otherwise a negative errno.
*/ */
static int octeon_i2c_read(struct octeon_i2c *i2c, int target, static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
u8 *data, int length) u8 *data, u16 *rlength, bool recv_len)
{ {
int i, result; int i, result, length = *rlength;
u8 tmp; u8 tmp;
if (length < 1) if (length < 1)
...@@ -353,7 +335,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, ...@@ -353,7 +335,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
if (result) if (result)
return result; return result;
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target<<1) | 1); octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target << 1) | 1);
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB); octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
result = octeon_i2c_wait(i2c); result = octeon_i2c_wait(i2c);
...@@ -362,6 +344,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, ...@@ -362,6 +344,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) { if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) {
dev_err(i2c->dev, dev_err(i2c->dev,
"%s: bad status before read (0x%x)\n", "%s: bad status before read (0x%x)\n",
...@@ -369,7 +352,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, ...@@ -369,7 +352,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
return -EIO; return -EIO;
} }
if (i+1 < length) if (i + 1 < length)
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB | TWSI_CTL_AAK); TWSI_CTL_ENAB | TWSI_CTL_AAK);
else else
...@@ -381,37 +364,44 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, ...@@ -381,37 +364,44 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
return result; return result;
data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA); data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
if (recv_len && i == 0) {
if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) {
dev_err(i2c->dev,
"%s: read len > I2C_SMBUS_BLOCK_MAX %d\n",
__func__, data[i]);
return -EPROTO;
}
length += data[i];
} }
}
*rlength = length;
return 0; return 0;
} }
/** /**
* octeon_i2c_xfer - The driver's master_xfer function. * octeon_i2c_xfer - The driver's master_xfer function
* @adap: Pointer to the i2c_adapter structure. * @adap: Pointer to the i2c_adapter structure
* @msgs: Pointer to the messages to be processed. * @msgs: Pointer to the messages to be processed
* @num: Length of the MSGS array. * @num: Length of the MSGS array
* *
* Returns the number of messages processed, or a negative errno on * Returns the number of messages processed, or a negative errno on failure.
* failure.
*/ */
static int octeon_i2c_xfer(struct i2c_adapter *adap, static int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
struct i2c_msg *msgs,
int num) int num)
{ {
struct i2c_msg *pmsg;
int i;
int ret = 0;
struct octeon_i2c *i2c = i2c_get_adapdata(adap); struct octeon_i2c *i2c = i2c_get_adapdata(adap);
int i, ret = 0;
for (i = 0; ret == 0 && i < num; i++) { for (i = 0; ret == 0 && i < num; i++) {
pmsg = &msgs[i]; struct i2c_msg *pmsg = &msgs[i];
dev_dbg(i2c->dev, dev_dbg(i2c->dev,
"Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n", "Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->len, pmsg->addr, i + 1, num); pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD) if (pmsg->flags & I2C_M_RD)
ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf, ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
pmsg->len); &pmsg->len, pmsg->flags & I2C_M_RECV_LEN);
else else
ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf, ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
pmsg->len); pmsg->len);
...@@ -423,7 +413,8 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap, ...@@ -423,7 +413,8 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap,
static u32 octeon_i2c_functionality(struct i2c_adapter *adap) static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
} }
static const struct i2c_algorithm octeon_i2c_algo = { static const struct i2c_algorithm octeon_i2c_algo = {
...@@ -438,10 +429,8 @@ static struct i2c_adapter octeon_i2c_ops = { ...@@ -438,10 +429,8 @@ static struct i2c_adapter octeon_i2c_ops = {
.timeout = HZ / 50, .timeout = HZ / 50,
}; };
/** /* calculate and set clock divisors */
* octeon_i2c_setclock - Calculate and set clock divisors. static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
*/
static int octeon_i2c_setclock(struct octeon_i2c *i2c)
{ {
int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff; int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000; int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
...@@ -449,8 +438,7 @@ static int octeon_i2c_setclock(struct octeon_i2c *i2c) ...@@ -449,8 +438,7 @@ static int octeon_i2c_setclock(struct octeon_i2c *i2c)
for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) { for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
/* /*
* An mdiv value of less than 2 seems to not work well * An mdiv value of less than 2 seems to not work well
* with ds1337 RTCs, so we constrain it to larger * with ds1337 RTCs, so we constrain it to larger values.
* values.
*/ */
for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) { for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
/* /*
...@@ -460,6 +448,7 @@ static int octeon_i2c_setclock(struct octeon_i2c *i2c) ...@@ -460,6 +448,7 @@ static int octeon_i2c_setclock(struct octeon_i2c *i2c)
tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10; tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
tclk *= (1 << ndiv_idx); tclk *= (1 << ndiv_idx);
thp_base = (i2c->sys_freq / (tclk * 2)) - 1; thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
for (inc = 0; inc <= 1; inc++) { for (inc = 0; inc <= 1; inc++) {
thp_idx = thp_base + inc; thp_idx = thp_base + inc;
if (thp_idx < 5 || thp_idx > 0xff) if (thp_idx < 5 || thp_idx > 0xff)
...@@ -480,11 +469,9 @@ static int octeon_i2c_setclock(struct octeon_i2c *i2c) ...@@ -480,11 +469,9 @@ static int octeon_i2c_setclock(struct octeon_i2c *i2c)
} }
octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp); octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv); octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
return 0;
} }
static int octeon_i2c_initlowlevel(struct octeon_i2c *i2c) static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
{ {
u8 status; u8 status;
int tries; int tries;
...@@ -507,9 +494,10 @@ static int octeon_i2c_initlowlevel(struct octeon_i2c *i2c) ...@@ -507,9 +494,10 @@ static int octeon_i2c_initlowlevel(struct octeon_i2c *i2c)
static int octeon_i2c_probe(struct platform_device *pdev) static int octeon_i2c_probe(struct platform_device *pdev)
{ {
int irq, result = 0; struct device_node *node = pdev->dev.of_node;
struct octeon_i2c *i2c;
struct resource *res_mem; struct resource *res_mem;
struct octeon_i2c *i2c;
int irq, result = 0;
/* All adaptors have an irq. */ /* All adaptors have an irq. */
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
...@@ -518,31 +506,25 @@ static int octeon_i2c_probe(struct platform_device *pdev) ...@@ -518,31 +506,25 @@ static int octeon_i2c_probe(struct platform_device *pdev)
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c) { if (!i2c) {
dev_err(&pdev->dev, "kzalloc failed\n");
result = -ENOMEM; result = -ENOMEM;
goto out; goto out;
} }
i2c->dev = &pdev->dev; i2c->dev = &pdev->dev;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem);
if (res_mem == NULL) { if (IS_ERR(i2c->twsi_base)) {
dev_err(i2c->dev, "found no memory resource\n"); result = PTR_ERR(i2c->twsi_base);
result = -ENXIO;
goto out; goto out;
} }
i2c->twsi_phys = res_mem->start;
i2c->regsize = resource_size(res_mem);
/* /*
* "clock-rate" is a legacy binding, the official binding is * "clock-rate" is a legacy binding, the official binding is
* "clock-frequency". Try the official one first and then * "clock-frequency". Try the official one first and then
* fall back if it doesn't exist. * fall back if it doesn't exist.
*/ */
if (of_property_read_u32(pdev->dev.of_node, if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) &&
"clock-frequency", &i2c->twsi_freq) && of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) {
of_property_read_u32(pdev->dev.of_node,
"clock-rate", &i2c->twsi_freq)) {
dev_err(i2c->dev, dev_err(i2c->dev,
"no I2C 'clock-rate' or 'clock-frequency' property\n"); "no I2C 'clock-rate' or 'clock-frequency' property\n");
result = -ENXIO; result = -ENXIO;
...@@ -551,13 +533,6 @@ static int octeon_i2c_probe(struct platform_device *pdev) ...@@ -551,13 +533,6 @@ static int octeon_i2c_probe(struct platform_device *pdev)
i2c->sys_freq = octeon_get_io_clock_rate(); i2c->sys_freq = octeon_get_io_clock_rate();
if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize,
res_mem->name)) {
dev_err(i2c->dev, "request_mem_region failed\n");
goto out;
}
i2c->twsi_base = devm_ioremap(&pdev->dev, i2c->twsi_phys, i2c->regsize);
init_waitqueue_head(&i2c->queue); init_waitqueue_head(&i2c->queue);
i2c->irq = irq; i2c->irq = irq;
...@@ -569,21 +544,17 @@ static int octeon_i2c_probe(struct platform_device *pdev) ...@@ -569,21 +544,17 @@ static int octeon_i2c_probe(struct platform_device *pdev)
goto out; goto out;
} }
result = octeon_i2c_initlowlevel(i2c); result = octeon_i2c_init_lowlevel(i2c);
if (result) { if (result) {
dev_err(i2c->dev, "init low level failed\n"); dev_err(i2c->dev, "init low level failed\n");
goto out; goto out;
} }
result = octeon_i2c_setclock(i2c); octeon_i2c_set_clock(i2c);
if (result) {
dev_err(i2c->dev, "clock init failed\n");
goto out;
}
i2c->adap = octeon_i2c_ops; i2c->adap = octeon_i2c_ops;
i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.parent = &pdev->dev;
i2c->adap.dev.of_node = pdev->dev.of_node; i2c->adap.dev.of_node = node;
i2c_set_adapdata(&i2c->adap, i2c); i2c_set_adapdata(&i2c->adap, i2c);
platform_set_drvdata(pdev, i2c); platform_set_drvdata(pdev, i2c);
...@@ -592,8 +563,7 @@ static int octeon_i2c_probe(struct platform_device *pdev) ...@@ -592,8 +563,7 @@ static int octeon_i2c_probe(struct platform_device *pdev)
dev_err(i2c->dev, "failed to add adapter\n"); dev_err(i2c->dev, "failed to add adapter\n");
goto out; goto out;
} }
dev_info(i2c->dev, "version %s\n", DRV_VERSION); dev_info(i2c->dev, "probed\n");
return 0; return 0;
out: out:
...@@ -608,10 +578,8 @@ static int octeon_i2c_remove(struct platform_device *pdev) ...@@ -608,10 +578,8 @@ static int octeon_i2c_remove(struct platform_device *pdev)
return 0; return 0;
}; };
static struct of_device_id octeon_i2c_match[] = { static const struct of_device_id octeon_i2c_match[] = {
{ { .compatible = "cavium,octeon-3860-twsi", },
.compatible = "cavium,octeon-3860-twsi",
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, octeon_i2c_match); MODULE_DEVICE_TABLE(of, octeon_i2c_match);
...@@ -630,4 +598,3 @@ module_platform_driver(octeon_i2c_driver); ...@@ -630,4 +598,3 @@ module_platform_driver(octeon_i2c_driver);
MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
...@@ -85,8 +85,14 @@ ...@@ -85,8 +85,14 @@
/* SB800 constants */ /* SB800 constants */
#define SB800_PIIX4_SMB_IDX 0xcd6 #define SB800_PIIX4_SMB_IDX 0xcd6
/* SB800 port is selected by bits 2:1 of the smb_en register (0x2c) */ /*
* SB800 port is selected by bits 2:1 of the smb_en register (0x2c)
* or the smb_sel register (0x2e), depending on bit 0 of register 0x2f.
* Hudson-2/Bolton port is always selected by bits 2:1 of register 0x2f.
*/
#define SB800_PIIX4_PORT_IDX 0x2c #define SB800_PIIX4_PORT_IDX 0x2c
#define SB800_PIIX4_PORT_IDX_ALT 0x2e
#define SB800_PIIX4_PORT_IDX_SEL 0x2f
#define SB800_PIIX4_PORT_IDX_MASK 0x06 #define SB800_PIIX4_PORT_IDX_MASK 0x06
/* insmod parameters */ /* insmod parameters */
...@@ -136,8 +142,13 @@ static const struct dmi_system_id piix4_dmi_ibm[] = { ...@@ -136,8 +142,13 @@ static const struct dmi_system_id piix4_dmi_ibm[] = {
{ }, { },
}; };
/* SB800 globals */ /*
* SB800 globals
* piix4_mutex_sb800 protects piix4_port_sel_sb800 and the pair
* of I/O ports at SB800_PIIX4_SMB_IDX.
*/
static DEFINE_MUTEX(piix4_mutex_sb800); static DEFINE_MUTEX(piix4_mutex_sb800);
static u8 piix4_port_sel_sb800;
static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = { static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = {
" port 0", " port 2", " port 3", " port 4" " port 0", " port 2", " port 3", " port 4"
}; };
...@@ -148,7 +159,7 @@ struct i2c_piix4_adapdata { ...@@ -148,7 +159,7 @@ struct i2c_piix4_adapdata {
/* SB800 */ /* SB800 */
bool sb800_main; bool sb800_main;
unsigned short port; u8 port; /* Port number, shifted */
}; };
static int piix4_setup(struct pci_dev *PIIX4_dev, static int piix4_setup(struct pci_dev *PIIX4_dev,
...@@ -254,7 +265,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -254,7 +265,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id, u8 aux) const struct pci_device_id *id, u8 aux)
{ {
unsigned short piix4_smba; unsigned short piix4_smba;
u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status; u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status, port_sel;
u8 i2ccfg, i2ccfg_offset = 0x10; u8 i2ccfg, i2ccfg_offset = 0x10;
/* SB800 and later SMBus does not support forcing address */ /* SB800 and later SMBus does not support forcing address */
...@@ -334,6 +345,23 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -334,6 +345,23 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
"SMBus Host Controller at 0x%x, revision %d\n", "SMBus Host Controller at 0x%x, revision %d\n",
piix4_smba, i2ccfg >> 4); piix4_smba, i2ccfg >> 4);
/* Find which register is used for port selection */
if (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD) {
piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_ALT;
} else {
mutex_lock(&piix4_mutex_sb800);
outb_p(SB800_PIIX4_PORT_IDX_SEL, SB800_PIIX4_SMB_IDX);
port_sel = inb_p(SB800_PIIX4_SMB_IDX + 1);
piix4_port_sel_sb800 = (port_sel & 0x01) ?
SB800_PIIX4_PORT_IDX_ALT :
SB800_PIIX4_PORT_IDX;
mutex_unlock(&piix4_mutex_sb800);
}
dev_info(&PIIX4_dev->dev,
"Using register 0x%02x for SMBus port selection\n",
(unsigned int)piix4_port_sel_sb800);
return piix4_smba; return piix4_smba;
} }
...@@ -563,12 +591,12 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, ...@@ -563,12 +591,12 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
mutex_lock(&piix4_mutex_sb800); mutex_lock(&piix4_mutex_sb800);
outb_p(SB800_PIIX4_PORT_IDX, SB800_PIIX4_SMB_IDX); outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
port = adapdata->port; port = adapdata->port;
if ((smba_en_lo & SB800_PIIX4_PORT_IDX_MASK) != (port << 1)) if ((smba_en_lo & SB800_PIIX4_PORT_IDX_MASK) != port)
outb_p((smba_en_lo & ~SB800_PIIX4_PORT_IDX_MASK) | (port << 1), outb_p((smba_en_lo & ~SB800_PIIX4_PORT_IDX_MASK) | port,
SB800_PIIX4_SMB_IDX + 1); SB800_PIIX4_SMB_IDX + 1);
retval = piix4_access(adap, addr, flags, read_write, retval = piix4_access(adap, addr, flags, read_write,
...@@ -627,7 +655,7 @@ static struct i2c_adapter *piix4_main_adapters[PIIX4_MAX_ADAPTERS]; ...@@ -627,7 +655,7 @@ static struct i2c_adapter *piix4_main_adapters[PIIX4_MAX_ADAPTERS];
static struct i2c_adapter *piix4_aux_adapter; static struct i2c_adapter *piix4_aux_adapter;
static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
bool sb800_main, unsigned short port, bool sb800_main, u8 port,
const char *name, struct i2c_adapter **padap) const char *name, struct i2c_adapter **padap)
{ {
struct i2c_adapter *adap; struct i2c_adapter *adap;
...@@ -654,7 +682,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, ...@@ -654,7 +682,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
adapdata->smba = smba; adapdata->smba = smba;
adapdata->sb800_main = sb800_main; adapdata->sb800_main = sb800_main;
adapdata->port = port; adapdata->port = port << 1;
/* set up the sysfs linkage to our parent device */ /* set up the sysfs linkage to our parent device */
adap->dev.parent = &dev->dev; adap->dev.parent = &dev->dev;
...@@ -790,7 +818,7 @@ static void piix4_adap_remove(struct i2c_adapter *adap) ...@@ -790,7 +818,7 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
if (adapdata->smba) { if (adapdata->smba) {
i2c_del_adapter(adap); i2c_del_adapter(adap);
if (adapdata->port == 0) { if (adapdata->port == (0 << 1)) {
release_region(adapdata->smba, SMBIOSIZE); release_region(adapdata->smba, SMBIOSIZE);
if (adapdata->sb800_main) if (adapdata->sb800_main)
release_region(SB800_PIIX4_SMB_IDX, 2); release_region(SB800_PIIX4_SMB_IDX, 2);
......
...@@ -14,8 +14,12 @@ ...@@ -14,8 +14,12 @@
* *
*/ */
#include <linux/atomic.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -24,6 +28,7 @@ ...@@ -24,6 +28,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
/* QUP Registers */ /* QUP Registers */
#define QUP_CONFIG 0x000 #define QUP_CONFIG 0x000
...@@ -33,6 +38,7 @@ ...@@ -33,6 +38,7 @@
#define QUP_OPERATIONAL 0x018 #define QUP_OPERATIONAL 0x018
#define QUP_ERROR_FLAGS 0x01c #define QUP_ERROR_FLAGS 0x01c
#define QUP_ERROR_FLAGS_EN 0x020 #define QUP_ERROR_FLAGS_EN 0x020
#define QUP_OPERATIONAL_MASK 0x028
#define QUP_HW_VERSION 0x030 #define QUP_HW_VERSION 0x030
#define QUP_MX_OUTPUT_CNT 0x100 #define QUP_MX_OUTPUT_CNT 0x100
#define QUP_OUT_FIFO_BASE 0x110 #define QUP_OUT_FIFO_BASE 0x110
...@@ -42,6 +48,7 @@ ...@@ -42,6 +48,7 @@
#define QUP_IN_FIFO_BASE 0x218 #define QUP_IN_FIFO_BASE 0x218
#define QUP_I2C_CLK_CTL 0x400 #define QUP_I2C_CLK_CTL 0x400
#define QUP_I2C_STATUS 0x404 #define QUP_I2C_STATUS 0x404
#define QUP_I2C_MASTER_GEN 0x408
/* QUP States and reset values */ /* QUP States and reset values */
#define QUP_RESET_STATE 0 #define QUP_RESET_STATE 0
...@@ -51,6 +58,7 @@ ...@@ -51,6 +58,7 @@
#define QUP_STATE_VALID BIT(2) #define QUP_STATE_VALID BIT(2)
#define QUP_I2C_MAST_GEN BIT(4) #define QUP_I2C_MAST_GEN BIT(4)
#define QUP_I2C_FLUSH BIT(6)
#define QUP_OPERATIONAL_RESET 0x000ff0 #define QUP_OPERATIONAL_RESET 0x000ff0
#define QUP_I2C_STATUS_RESET 0xfffffc #define QUP_I2C_STATUS_RESET 0xfffffc
...@@ -69,16 +77,22 @@ ...@@ -69,16 +77,22 @@
#define QUP_CLOCK_AUTO_GATE BIT(13) #define QUP_CLOCK_AUTO_GATE BIT(13)
#define I2C_MINI_CORE (2 << 8) #define I2C_MINI_CORE (2 << 8)
#define I2C_N_VAL 15 #define I2C_N_VAL 15
#define I2C_N_VAL_V2 7
/* Most significant word offset in FIFO port */ /* Most significant word offset in FIFO port */
#define QUP_MSW_SHIFT (I2C_N_VAL + 1) #define QUP_MSW_SHIFT (I2C_N_VAL + 1)
/* Packing/Unpacking words in FIFOs, and IO modes */ /* Packing/Unpacking words in FIFOs, and IO modes */
#define QUP_OUTPUT_BLK_MODE (1 << 10) #define QUP_OUTPUT_BLK_MODE (1 << 10)
#define QUP_OUTPUT_BAM_MODE (3 << 10)
#define QUP_INPUT_BLK_MODE (1 << 12) #define QUP_INPUT_BLK_MODE (1 << 12)
#define QUP_INPUT_BAM_MODE (3 << 12)
#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE)
#define QUP_UNPACK_EN BIT(14) #define QUP_UNPACK_EN BIT(14)
#define QUP_PACK_EN BIT(15) #define QUP_PACK_EN BIT(15)
#define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN) #define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN)
#define QUP_V2_TAGS_EN 1
#define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03) #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03)
#define QUP_OUTPUT_FIFO_SIZE(x) (((x) >> 2) & 0x07) #define QUP_OUTPUT_FIFO_SIZE(x) (((x) >> 2) & 0x07)
...@@ -90,6 +104,15 @@ ...@@ -90,6 +104,15 @@
#define QUP_TAG_DATA (2 << 8) #define QUP_TAG_DATA (2 << 8)
#define QUP_TAG_STOP (3 << 8) #define QUP_TAG_STOP (3 << 8)
#define QUP_TAG_REC (4 << 8) #define QUP_TAG_REC (4 << 8)
#define QUP_BAM_INPUT_EOT 0x93
#define QUP_BAM_FLUSH_STOP 0x96
/* QUP v2 tags */
#define QUP_TAG_V2_START 0x81
#define QUP_TAG_V2_DATAWR 0x82
#define QUP_TAG_V2_DATAWR_STOP 0x83
#define QUP_TAG_V2_DATARD 0x85
#define QUP_TAG_V2_DATARD_STOP 0x87
/* Status, Error flags */ /* Status, Error flags */
#define I2C_STATUS_WR_BUFFER_FULL BIT(0) #define I2C_STATUS_WR_BUFFER_FULL BIT(0)
...@@ -98,6 +121,36 @@ ...@@ -98,6 +121,36 @@
#define QUP_STATUS_ERROR_FLAGS 0x7c #define QUP_STATUS_ERROR_FLAGS 0x7c
#define QUP_READ_LIMIT 256 #define QUP_READ_LIMIT 256
#define SET_BIT 0x1
#define RESET_BIT 0x0
#define ONE_BYTE 0x1
#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31)
#define MX_TX_RX_LEN SZ_64K
#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT)
/* Max timeout in ms for 32k bytes */
#define TOUT_MAX 300
struct qup_i2c_block {
int count;
int pos;
int tx_tag_len;
int rx_tag_len;
int data_len;
u8 tags[6];
};
struct qup_i2c_tag {
u8 *start;
dma_addr_t addr;
};
struct qup_i2c_bam {
struct qup_i2c_tag tag;
struct dma_chan *dma;
struct scatterlist *sg;
};
struct qup_i2c_dev { struct qup_i2c_dev {
struct device *dev; struct device *dev;
...@@ -114,6 +167,7 @@ struct qup_i2c_dev { ...@@ -114,6 +167,7 @@ struct qup_i2c_dev {
int in_blk_sz; int in_blk_sz;
unsigned long one_byte_t; unsigned long one_byte_t;
struct qup_i2c_block blk;
struct i2c_msg *msg; struct i2c_msg *msg;
/* Current posion in user message buffer */ /* Current posion in user message buffer */
...@@ -123,6 +177,19 @@ struct qup_i2c_dev { ...@@ -123,6 +177,19 @@ struct qup_i2c_dev {
/* QUP core errors */ /* QUP core errors */
u32 qup_err; u32 qup_err;
/* To check if this is the last msg */
bool is_last;
/* To configure when bus is in run state */
int config_run;
/* dma parameters */
bool is_dma;
struct dma_pool *dpool;
struct qup_i2c_tag start_tag;
struct qup_i2c_bam brx;
struct qup_i2c_bam btx;
struct completion xfer; struct completion xfer;
}; };
...@@ -199,6 +266,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state) ...@@ -199,6 +266,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK); return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
} }
static void qup_i2c_flush(struct qup_i2c_dev *qup)
{
u32 val = readl(qup->base + QUP_STATE);
val |= QUP_I2C_FLUSH;
writel(val, qup->base + QUP_STATE);
}
static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup) static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
{ {
return qup_i2c_poll_state_mask(qup, 0, 0); return qup_i2c_poll_state_mask(qup, 0, 0);
...@@ -221,26 +296,62 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) ...@@ -221,26 +296,62 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
return 0; return 0;
} }
static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup) /**
* qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
* @qup: The qup_i2c_dev device
* @op: The bit/event to wait on
* @val: value of the bit to wait on, 0 or 1
* @len: The length the bytes to be transferred
*/
static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
int len)
{ {
unsigned long timeout; unsigned long timeout;
u32 opflags; u32 opflags;
u32 status; u32 status;
u32 shift = __ffs(op);
timeout = jiffies + HZ; len *= qup->one_byte_t;
/* timeout after a wait of twice the max time */
timeout = jiffies + len * 4;
for (;;) { for (;;) {
opflags = readl(qup->base + QUP_OPERATIONAL); opflags = readl(qup->base + QUP_OPERATIONAL);
status = readl(qup->base + QUP_I2C_STATUS); status = readl(qup->base + QUP_I2C_STATUS);
if (!(opflags & QUP_OUT_NOT_EMPTY) && if (((opflags & op) >> shift) == val) {
!(status & I2C_STATUS_BUS_ACTIVE)) if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) {
if (!(status & I2C_STATUS_BUS_ACTIVE))
return 0;
} else {
return 0; return 0;
}
}
if (time_after(jiffies, timeout)) if (time_after(jiffies, timeout))
return -ETIMEDOUT; return -ETIMEDOUT;
usleep_range(qup->one_byte_t, qup->one_byte_t * 2); usleep_range(len, len * 2);
}
}
static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
struct i2c_msg *msg)
{
/* Number of entries to shift out, including the tags */
int total = msg->len + qup->blk.tx_tag_len;
total |= qup->config_run;
if (total < qup->out_fifo_sz) {
/* FIFO mode */
writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
writel(total, qup->base + QUP_MX_WRITE_CNT);
} else {
/* BLOCK mode (transfer data on chunks) */
writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
qup->base + QUP_IO_MODE);
writel(total, qup->base + QUP_MX_OUTPUT_CNT);
} }
} }
...@@ -261,13 +372,45 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -261,13 +372,45 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
} }
} }
static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) static int check_for_fifo_space(struct qup_i2c_dev *qup)
{
int ret;
ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
if (ret)
goto out;
ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL,
RESET_BIT, 4 * ONE_BYTE);
if (ret) {
/* Fifo is full. Drain out the fifo */
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto out;
ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY,
RESET_BIT, 256 * ONE_BYTE);
if (ret) {
dev_err(qup->dev, "timeout for fifo out full");
goto out;
}
ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
if (ret)
goto out;
}
out:
return ret;
}
static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{ {
u32 addr = msg->addr << 1; u32 addr = msg->addr << 1;
u32 qup_tag; u32 qup_tag;
u32 opflags;
int idx; int idx;
u32 val; u32 val;
int ret = 0;
if (qup->pos == 0) { if (qup->pos == 0) {
val = QUP_TAG_START | addr; val = QUP_TAG_START | addr;
...@@ -279,9 +422,9 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -279,9 +422,9 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
while (qup->pos < msg->len) { while (qup->pos < msg->len) {
/* Check that there's space in the FIFO for our pair */ /* Check that there's space in the FIFO for our pair */
opflags = readl(qup->base + QUP_OPERATIONAL); ret = check_for_fifo_space(qup);
if (opflags & QUP_OUT_FULL) if (ret)
break; return ret;
if (qup->pos == msg->len - 1) if (qup->pos == msg->len - 1)
qup_tag = QUP_TAG_STOP; qup_tag = QUP_TAG_STOP;
...@@ -300,11 +443,501 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -300,11 +443,501 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
qup->pos++; qup->pos++;
idx++; idx++;
} }
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
return ret;
} }
static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
struct i2c_msg *msg)
{
memset(&qup->blk, 0, sizeof(qup->blk));
qup->blk.data_len = msg->len;
qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
/* 4 bytes for first block and 2 writes for rest */
qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
/* There are 2 tag bytes that are read in to fifo for every block */
if (msg->flags & I2C_M_RD)
qup->blk.rx_tag_len = qup->blk.count * 2;
}
static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
int dlen, u8 *dbuf)
{
u32 val = 0, idx = 0, pos = 0, i = 0, t;
int len = tlen + dlen;
u8 *buf = tbuf;
int ret = 0;
while (len > 0) {
ret = check_for_fifo_space(qup);
if (ret)
return ret;
t = (len >= 4) ? 4 : len;
while (idx < t) {
if (!i && (pos >= tlen)) {
buf = dbuf;
pos = 0;
i = 1;
}
val |= buf[pos++] << (idx++ * 8);
}
writel(val, qup->base + QUP_OUT_FIFO_BASE);
idx = 0;
val = 0;
len -= 4;
}
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
return ret;
}
static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
{
int data_len;
if (qup->blk.data_len > QUP_READ_LIMIT)
data_len = QUP_READ_LIMIT;
else
data_len = qup->blk.data_len;
return data_len;
}
static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
struct i2c_msg *msg, int is_dma)
{
u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
int len = 0;
int data_len;
int last = (qup->blk.pos == (qup->blk.count - 1)) && (qup->is_last);
if (qup->blk.pos == 0) {
tags[len++] = QUP_TAG_V2_START;
tags[len++] = addr & 0xff;
if (msg->flags & I2C_M_TEN)
tags[len++] = addr >> 8;
}
/* Send _STOP commands for the last block */
if (last) {
if (msg->flags & I2C_M_RD)
tags[len++] = QUP_TAG_V2_DATARD_STOP;
else
tags[len++] = QUP_TAG_V2_DATAWR_STOP;
} else {
if (msg->flags & I2C_M_RD)
tags[len++] = QUP_TAG_V2_DATARD;
else
tags[len++] = QUP_TAG_V2_DATAWR;
}
data_len = qup_i2c_get_data_len(qup);
/* 0 implies 256 bytes */
if (data_len == QUP_READ_LIMIT)
tags[len++] = 0;
else
tags[len++] = data_len;
if ((msg->flags & I2C_M_RD) && last && is_dma) {
tags[len++] = QUP_BAM_INPUT_EOT;
tags[len++] = QUP_BAM_FLUSH_STOP;
}
return len;
}
static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
int data_len = 0, tag_len, index;
int ret;
tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg, 0);
index = msg->len - qup->blk.data_len;
/* only tags are written for read */
if (!(msg->flags & I2C_M_RD))
data_len = qup_i2c_get_data_len(qup);
ret = qup_i2c_send_data(qup, tag_len, qup->blk.tags,
data_len, &msg->buf[index]);
qup->blk.data_len -= data_len;
return ret;
}
static void qup_i2c_bam_cb(void *data)
{
struct qup_i2c_dev *qup = data;
complete(&qup->xfer);
}
static int qup_sg_set_buf(struct scatterlist *sg, void *buf,
struct qup_i2c_tag *tg, unsigned int buflen,
struct qup_i2c_dev *qup, int map, int dir)
{
int ret;
sg_set_buf(sg, buf, buflen);
ret = dma_map_sg(qup->dev, sg, 1, dir);
if (!ret)
return -EINVAL;
if (!map)
sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);
return 0;
}
static void qup_i2c_rel_dma(struct qup_i2c_dev *qup)
{
if (qup->btx.dma)
dma_release_channel(qup->btx.dma);
if (qup->brx.dma)
dma_release_channel(qup->brx.dma);
qup->btx.dma = NULL;
qup->brx.dma = NULL;
}
static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
{
int err;
if (!qup->btx.dma) {
qup->btx.dma = dma_request_slave_channel_reason(qup->dev, "tx");
if (IS_ERR(qup->btx.dma)) {
err = PTR_ERR(qup->btx.dma);
qup->btx.dma = NULL;
dev_err(qup->dev, "\n tx channel not available");
return err;
}
}
if (!qup->brx.dma) {
qup->brx.dma = dma_request_slave_channel_reason(qup->dev, "rx");
if (IS_ERR(qup->brx.dma)) {
dev_err(qup->dev, "\n rx channel not available");
err = PTR_ERR(qup->brx.dma);
qup->brx.dma = NULL;
qup_i2c_rel_dma(qup);
return err;
}
}
return 0;
}
static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
int num)
{
struct dma_async_tx_descriptor *txd, *rxd = NULL;
int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
dma_cookie_t cookie_rx, cookie_tx;
u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
u8 *tags;
while (idx < num) {
blocks = (msg->len + limit) / limit;
rem = msg->len % limit;
tx_len = 0, len = 0, i = 0;
qup->is_last = (idx == (num - 1));
qup_i2c_set_blk_data(qup, msg);
if (msg->flags & I2C_M_RD) {
rx_nents += (blocks * 2) + 1;
tx_nents += 1;
while (qup->blk.pos < blocks) {
/* length set to '0' implies 256 bytes */
tlen = (i == (blocks - 1)) ? rem : 0;
tags = &qup->start_tag.start[off + len];
len += qup_i2c_set_tags(tags, qup, msg, 1);
/* scratch buf to read the start and len tags */
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&qup->brx.tag.start[0],
&qup->brx.tag,
2, qup, 0, 0);
if (ret)
return ret;
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&msg->buf[limit * i],
NULL, tlen, qup,
1, DMA_FROM_DEVICE);
if (ret)
return ret;
i++;
qup->blk.pos = i;
}
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&qup->start_tag.start[off],
&qup->start_tag, len, qup, 0, 0);
if (ret)
return ret;
off += len;
/* scratch buf to read the BAM EOT and FLUSH tags */
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&qup->brx.tag.start[0],
&qup->brx.tag, 2,
qup, 0, 0);
if (ret)
return ret;
} else {
tx_nents += (blocks * 2);
while (qup->blk.pos < blocks) {
tlen = (i == (blocks - 1)) ? rem : 0;
tags = &qup->start_tag.start[off + tx_len];
len = qup_i2c_set_tags(tags, qup, msg, 1);
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
tags,
&qup->start_tag, len,
qup, 0, 0);
if (ret)
return ret;
tx_len += len;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&msg->buf[limit * i],
NULL, tlen, qup, 1,
DMA_TO_DEVICE);
if (ret)
return ret;
i++;
qup->blk.pos = i;
}
off += tx_len;
if (idx == (num - 1)) {
len = 1;
if (rx_nents) {
qup->btx.tag.start[0] =
QUP_BAM_INPUT_EOT;
len++;
}
qup->btx.tag.start[len - 1] =
QUP_BAM_FLUSH_STOP;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&qup->btx.tag.start[0],
&qup->btx.tag, len,
qup, 0, 0);
if (ret)
return ret;
tx_nents += 1;
}
}
idx++;
msg++;
}
txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_nents,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
if (!txd) {
dev_err(qup->dev, "failed to get tx desc\n");
ret = -EINVAL;
goto desc_err;
}
if (!rx_nents) {
txd->callback = qup_i2c_bam_cb;
txd->callback_param = qup;
}
cookie_tx = dmaengine_submit(txd);
if (dma_submit_error(cookie_tx)) {
ret = -EINVAL;
goto desc_err;
}
dma_async_issue_pending(qup->btx.dma);
if (rx_nents) {
rxd = dmaengine_prep_slave_sg(qup->brx.dma, qup->brx.sg,
rx_nents, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!rxd) {
dev_err(qup->dev, "failed to get rx desc\n");
ret = -EINVAL;
/* abort TX descriptors */
dmaengine_terminate_all(qup->btx.dma);
goto desc_err;
}
rxd->callback = qup_i2c_bam_cb;
rxd->callback_param = qup;
cookie_rx = dmaengine_submit(rxd);
if (dma_submit_error(cookie_rx)) {
ret = -EINVAL;
goto desc_err;
}
dma_async_issue_pending(qup->brx.dma);
}
if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
dev_err(qup->dev, "normal trans timed out\n");
ret = -ETIMEDOUT;
}
if (ret || qup->bus_err || qup->qup_err) {
if (qup->bus_err & QUP_I2C_NACK_FLAG) {
msg--;
dev_err(qup->dev, "NACK from %x\n", msg->addr);
ret = -EIO;
if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
dev_err(qup->dev, "change to run state timed out");
return ret;
}
if (rx_nents)
writel(QUP_BAM_INPUT_EOT,
qup->base + QUP_OUT_FIFO_BASE);
writel(QUP_BAM_FLUSH_STOP,
qup->base + QUP_OUT_FIFO_BASE);
qup_i2c_flush(qup);
/* wait for remaining interrupts to occur */
if (!wait_for_completion_timeout(&qup->xfer, HZ))
dev_err(qup->dev, "flush timed out\n");
qup_i2c_rel_dma(qup);
}
}
dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE);
if (rx_nents)
dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents,
DMA_FROM_DEVICE);
desc_err:
return ret;
}
static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
int num)
{
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
int ret = 0;
enable_irq(qup->irq);
ret = qup_i2c_req_dma(qup);
if (ret)
goto out;
qup->bus_err = 0;
qup->qup_err = 0;
writel(0, qup->base + QUP_MX_INPUT_CNT);
writel(0, qup->base + QUP_MX_OUTPUT_CNT);
/* set BAM mode */
writel(QUP_REPACK_EN | QUP_BAM_MODE, qup->base + QUP_IO_MODE);
/* mask fifo irqs */
writel((0x3 << 8), qup->base + QUP_OPERATIONAL_MASK);
/* set RUN STATE */
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto out;
writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
qup->msg = msg;
ret = qup_i2c_bam_do_xfer(qup, qup->msg, num);
out:
disable_irq(qup->irq);
qup->msg = NULL;
return ret;
}
static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
struct i2c_msg *msg)
{ {
unsigned long left; unsigned long left;
int ret = 0;
left = wait_for_completion_timeout(&qup->xfer, HZ);
if (!left) {
writel(1, qup->base + QUP_SW_RESET);
ret = -ETIMEDOUT;
}
if (qup->bus_err || qup->qup_err) {
if (qup->bus_err & QUP_I2C_NACK_FLAG) {
dev_err(qup->dev, "NACK from %x\n", msg->addr);
ret = -EIO;
}
}
return ret;
}
static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
int ret = 0;
qup->msg = msg;
qup->pos = 0;
enable_irq(qup->irq);
qup_i2c_set_blk_data(qup, msg);
qup_i2c_set_write_mode_v2(qup, msg);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto err;
writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
do {
ret = qup_i2c_issue_xfer_v2(qup, msg);
if (ret)
goto err;
ret = qup_i2c_wait_for_complete(qup, msg);
if (ret)
goto err;
qup->blk.pos++;
} while (qup->blk.pos < qup->blk.count);
ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
err:
disable_irq(qup->irq);
qup->msg = NULL;
return ret;
}
static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
int ret; int ret;
qup->msg = msg; qup->msg = msg;
...@@ -325,30 +958,21 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -325,30 +958,21 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
if (ret) if (ret)
goto err; goto err;
qup_i2c_issue_write(qup, msg); ret = qup_i2c_issue_write(qup, msg);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret) if (ret)
goto err; goto err;
left = wait_for_completion_timeout(&qup->xfer, HZ); ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (!left) { if (ret)
writel(1, qup->base + QUP_SW_RESET);
ret = -ETIMEDOUT;
goto err; goto err;
}
if (qup->bus_err || qup->qup_err) { ret = qup_i2c_wait_for_complete(qup, msg);
if (qup->bus_err & QUP_I2C_NACK_FLAG) if (ret)
dev_err(qup->dev, "NACK from %x\n", msg->addr);
ret = -EIO;
goto err; goto err;
}
} while (qup->pos < msg->len); } while (qup->pos < msg->len);
/* Wait for the outstanding data in the fifo to drain */ /* Wait for the outstanding data in the fifo to drain */
ret = qup_i2c_wait_writeready(qup); ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
err: err:
disable_irq(qup->irq); disable_irq(qup->irq);
qup->msg = NULL; qup->msg = NULL;
...@@ -370,6 +994,28 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len) ...@@ -370,6 +994,28 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
} }
} }
static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
{
int tx_len = qup->blk.tx_tag_len;
len += qup->blk.rx_tag_len;
len |= qup->config_run;
tx_len |= qup->config_run;
if (len < qup->in_fifo_sz) {
/* FIFO mode */
writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
writel(len, qup->base + QUP_MX_READ_CNT);
} else {
/* BLOCK mode (transfer data on chunks) */
writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
qup->base + QUP_IO_MODE);
writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
writel(len, qup->base + QUP_MX_INPUT_CNT);
}
}
static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{ {
u32 addr, len, val; u32 addr, len, val;
...@@ -384,18 +1030,19 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -384,18 +1030,19 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
} }
static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg) static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{ {
u32 opflags;
u32 val = 0; u32 val = 0;
int idx; int idx;
int ret = 0;
for (idx = 0; qup->pos < msg->len; idx++) { for (idx = 0; qup->pos < msg->len; idx++) {
if ((idx & 1) == 0) { if ((idx & 1) == 0) {
/* Check that FIFO have data */ /* Check that FIFO have data */
opflags = readl(qup->base + QUP_OPERATIONAL); ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
if (!(opflags & QUP_IN_NOT_EMPTY)) SET_BIT, 4 * ONE_BYTE);
break; if (ret)
return ret;
/* Reading 2 words at time */ /* Reading 2 words at time */
val = readl(qup->base + QUP_IN_FIFO_BASE); val = readl(qup->base + QUP_IN_FIFO_BASE);
...@@ -405,18 +1052,94 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -405,18 +1052,94 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT; msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
} }
} }
return ret;
}
static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
struct i2c_msg *msg)
{
u32 val;
int idx, pos = 0, ret = 0, total;
total = qup_i2c_get_data_len(qup);
/* 2 extra bytes for read tags */
while (pos < (total + 2)) {
/* Check that FIFO have data */
ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
SET_BIT, 4 * ONE_BYTE);
if (ret) {
dev_err(qup->dev, "timeout for fifo not empty");
return ret;
}
val = readl(qup->base + QUP_IN_FIFO_BASE);
for (idx = 0; idx < 4; idx++, val >>= 8, pos++) {
/* first 2 bytes are tag bytes */
if (pos < 2)
continue;
if (pos >= (total + 2))
goto out;
msg->buf[qup->pos++] = val & 0xff;
}
}
out:
qup->blk.data_len -= total;
return ret;
}
static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{
int ret = 0;
qup->msg = msg;
qup->pos = 0;
enable_irq(qup->irq);
qup_i2c_set_blk_data(qup, msg);
qup_i2c_set_read_mode_v2(qup, msg->len);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
if (ret)
goto err;
writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
do {
ret = qup_i2c_issue_xfer_v2(qup, msg);
if (ret)
goto err;
ret = qup_i2c_wait_for_complete(qup, msg);
if (ret)
goto err;
ret = qup_i2c_read_fifo_v2(qup, msg);
if (ret)
goto err;
qup->blk.pos++;
} while (qup->blk.pos < qup->blk.count);
err:
disable_irq(qup->irq);
qup->msg = NULL;
return ret;
} }
static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{ {
unsigned long left;
int ret; int ret;
qup->msg = msg; qup->msg = msg;
qup->pos = 0; qup->pos = 0;
enable_irq(qup->irq); enable_irq(qup->irq);
qup_i2c_set_read_mode(qup, msg->len); qup_i2c_set_read_mode(qup, msg->len);
ret = qup_i2c_change_state(qup, QUP_RUN_STATE); ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
...@@ -436,21 +1159,13 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -436,21 +1159,13 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
goto err; goto err;
do { do {
left = wait_for_completion_timeout(&qup->xfer, HZ); ret = qup_i2c_wait_for_complete(qup, msg);
if (!left) { if (ret)
writel(1, qup->base + QUP_SW_RESET);
ret = -ETIMEDOUT;
goto err; goto err;
}
if (qup->bus_err || qup->qup_err) { ret = qup_i2c_read_fifo(qup, msg);
if (qup->bus_err & QUP_I2C_NACK_FLAG) if (ret)
dev_err(qup->dev, "NACK from %x\n", msg->addr);
ret = -EIO;
goto err; goto err;
}
qup_i2c_read_fifo(qup, msg);
} while (qup->pos < msg->len); } while (qup->pos < msg->len);
err: err:
...@@ -513,6 +1228,87 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, ...@@ -513,6 +1228,87 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
return ret; return ret;
} }
static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
struct i2c_msg msgs[],
int num)
{
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
int ret, len, idx = 0, use_dma = 0;
ret = pm_runtime_get_sync(qup->dev);
if (ret < 0)
goto out;
writel(1, qup->base + QUP_SW_RESET);
ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
if (ret)
goto out;
/* Configure QUP as I2C mini core */
writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
if ((qup->is_dma)) {
/* All i2c_msgs should be transferred using either dma or cpu */
for (idx = 0; idx < num; idx++) {
if (msgs[idx].len == 0) {
ret = -EINVAL;
goto out;
}
len = (msgs[idx].len > qup->out_fifo_sz) ||
(msgs[idx].len > qup->in_fifo_sz);
if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
use_dma = 1;
} else {
use_dma = 0;
break;
}
}
}
do {
if (msgs[idx].len == 0) {
ret = -EINVAL;
goto out;
}
if (qup_i2c_poll_state_i2c_master(qup)) {
ret = -EIO;
goto out;
}
qup->is_last = (idx == (num - 1));
if (idx)
qup->config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
else
qup->config_run = 0;
reinit_completion(&qup->xfer);
if (use_dma) {
ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
} else {
if (msgs[idx].flags & I2C_M_RD)
ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
else
ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
}
} while ((idx++ < (num - 1)) && !use_dma && !ret);
if (!ret)
ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
if (ret == 0)
ret = num;
out:
pm_runtime_mark_last_busy(qup->dev);
pm_runtime_put_autosuspend(qup->dev);
return ret;
}
static u32 qup_i2c_func(struct i2c_adapter *adap) static u32 qup_i2c_func(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
...@@ -523,6 +1319,11 @@ static const struct i2c_algorithm qup_i2c_algo = { ...@@ -523,6 +1319,11 @@ static const struct i2c_algorithm qup_i2c_algo = {
.functionality = qup_i2c_func, .functionality = qup_i2c_func,
}; };
static const struct i2c_algorithm qup_i2c_algo_v2 = {
.master_xfer = qup_i2c_xfer_v2,
.functionality = qup_i2c_func,
};
/* /*
* The QUP block will issue a NACK and STOP on the bus when reaching * The QUP block will issue a NACK and STOP on the bus when reaching
* the end of the read, the length of the read is specified as one byte * the end of the read, the length of the read is specified as one byte
...@@ -561,6 +1362,7 @@ static int qup_i2c_probe(struct platform_device *pdev) ...@@ -561,6 +1362,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
int ret, fs_div, hs_div; int ret, fs_div, hs_div;
int src_clk_freq; int src_clk_freq;
u32 clk_freq = 100000; u32 clk_freq = 100000;
int blocks;
qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL); qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
if (!qup) if (!qup)
...@@ -572,6 +1374,68 @@ static int qup_i2c_probe(struct platform_device *pdev) ...@@ -572,6 +1374,68 @@ static int qup_i2c_probe(struct platform_device *pdev)
of_property_read_u32(node, "clock-frequency", &clk_freq); of_property_read_u32(node, "clock-frequency", &clk_freq);
if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
qup->adap.algo = &qup_i2c_algo;
qup->adap.quirks = &qup_i2c_quirks;
} else {
qup->adap.algo = &qup_i2c_algo_v2;
ret = qup_i2c_req_dma(qup);
if (ret == -EPROBE_DEFER)
goto fail_dma;
else if (ret != 0)
goto nodma;
blocks = (MX_BLOCKS << 1) + 1;
qup->btx.sg = devm_kzalloc(&pdev->dev,
sizeof(*qup->btx.sg) * blocks,
GFP_KERNEL);
if (!qup->btx.sg) {
ret = -ENOMEM;
goto fail_dma;
}
sg_init_table(qup->btx.sg, blocks);
qup->brx.sg = devm_kzalloc(&pdev->dev,
sizeof(*qup->brx.sg) * blocks,
GFP_KERNEL);
if (!qup->brx.sg) {
ret = -ENOMEM;
goto fail_dma;
}
sg_init_table(qup->brx.sg, blocks);
/* 2 tag bytes for each block + 5 for start, stop tags */
size = blocks * 2 + 5;
qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev,
size, 4, 0);
qup->start_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
&qup->start_tag.addr);
if (!qup->start_tag.start) {
ret = -ENOMEM;
goto fail_dma;
}
qup->brx.tag.start = dma_pool_alloc(qup->dpool,
GFP_KERNEL,
&qup->brx.tag.addr);
if (!qup->brx.tag.start) {
ret = -ENOMEM;
goto fail_dma;
}
qup->btx.tag.start = dma_pool_alloc(qup->dpool,
GFP_KERNEL,
&qup->btx.tag.addr);
if (!qup->btx.tag.start) {
ret = -ENOMEM;
goto fail_dma;
}
qup->is_dma = true;
}
nodma:
/* We support frequencies up to FAST Mode (400KHz) */ /* We support frequencies up to FAST Mode (400KHz) */
if (!clk_freq || clk_freq > 400000) { if (!clk_freq || clk_freq > 400000) {
dev_err(qup->dev, "clock frequency not supported %d\n", dev_err(qup->dev, "clock frequency not supported %d\n",
...@@ -667,10 +1531,10 @@ static int qup_i2c_probe(struct platform_device *pdev) ...@@ -667,10 +1531,10 @@ static int qup_i2c_probe(struct platform_device *pdev)
qup->out_blk_sz, qup->out_fifo_sz); qup->out_blk_sz, qup->out_fifo_sz);
i2c_set_adapdata(&qup->adap, qup); i2c_set_adapdata(&qup->adap, qup);
qup->adap.algo = &qup_i2c_algo;
qup->adap.quirks = &qup_i2c_quirks;
qup->adap.dev.parent = qup->dev; qup->adap.dev.parent = qup->dev;
qup->adap.dev.of_node = pdev->dev.of_node; qup->adap.dev.of_node = pdev->dev.of_node;
qup->is_last = true;
strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name)); strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC); pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC);
...@@ -689,6 +1553,11 @@ static int qup_i2c_probe(struct platform_device *pdev) ...@@ -689,6 +1553,11 @@ static int qup_i2c_probe(struct platform_device *pdev)
pm_runtime_set_suspended(qup->dev); pm_runtime_set_suspended(qup->dev);
fail: fail:
qup_i2c_disable_clocks(qup); qup_i2c_disable_clocks(qup);
fail_dma:
if (qup->btx.dma)
dma_release_channel(qup->btx.dma);
if (qup->brx.dma)
dma_release_channel(qup->brx.dma);
return ret; return ret;
} }
...@@ -696,6 +1565,18 @@ static int qup_i2c_remove(struct platform_device *pdev) ...@@ -696,6 +1565,18 @@ static int qup_i2c_remove(struct platform_device *pdev)
{ {
struct qup_i2c_dev *qup = platform_get_drvdata(pdev); struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
if (qup->is_dma) {
dma_pool_free(qup->dpool, qup->start_tag.start,
qup->start_tag.addr);
dma_pool_free(qup->dpool, qup->brx.tag.start,
qup->brx.tag.addr);
dma_pool_free(qup->dpool, qup->btx.tag.start,
qup->btx.tag.addr);
dma_pool_destroy(qup->dpool);
dma_release_channel(qup->btx.dma);
dma_release_channel(qup->brx.dma);
}
disable_irq(qup->irq); disable_irq(qup->irq);
qup_i2c_disable_clocks(qup); qup_i2c_disable_clocks(qup);
i2c_del_adapter(&qup->adap); i2c_del_adapter(&qup->adap);
......
...@@ -611,7 +611,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) ...@@ -611,7 +611,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (IS_ERR(priv->io)) if (IS_ERR(priv->io))
return PTR_ERR(priv->io); return PTR_ERR(priv->io);
priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data; priv->devtype = (enum rcar_i2c_type)of_device_get_match_data(dev);
init_waitqueue_head(&priv->wait); init_waitqueue_head(&priv->wait);
adap = &priv->adap; adap = &priv->adap;
......
...@@ -805,9 +805,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) ...@@ -805,9 +805,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->hw = &tegra20_i2c_hw; i2c_dev->hw = &tegra20_i2c_hw;
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
const struct of_device_id *match; i2c_dev->hw = of_device_get_match_data(&pdev->dev);
match = of_match_device(tegra_i2c_of_match, &pdev->dev);
i2c_dev->hw = match->data;
i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
"nvidia,tegra20-i2c-dvc"); "nvidia,tegra20-i2c-dvc");
} else if (pdev->id == 3) { } else if (pdev->id == 3) {
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#define DRIVER_NAME "xiic-i2c" #define DRIVER_NAME "xiic-i2c"
...@@ -66,6 +68,7 @@ enum xiic_endian { ...@@ -66,6 +68,7 @@ enum xiic_endian {
* @endianness: big/little-endian byte order * @endianness: big/little-endian byte order
*/ */
struct xiic_i2c { struct xiic_i2c {
struct device *dev;
void __iomem *base; void __iomem *base;
wait_queue_head_t wait; wait_queue_head_t wait;
struct i2c_adapter adap; struct i2c_adapter adap;
...@@ -77,6 +80,7 @@ struct xiic_i2c { ...@@ -77,6 +80,7 @@ struct xiic_i2c {
struct i2c_msg *rx_msg; struct i2c_msg *rx_msg;
int rx_pos; int rx_pos;
enum xiic_endian endianness; enum xiic_endian endianness;
struct clk *clk;
}; };
...@@ -164,6 +168,7 @@ struct xiic_i2c { ...@@ -164,6 +168,7 @@ struct xiic_i2c {
#define XIIC_RESET_MASK 0xAUL #define XIIC_RESET_MASK 0xAUL
#define XIIC_PM_TIMEOUT 1000 /* ms */
/* /*
* The following constant is used for the device global interrupt enable * The following constant is used for the device global interrupt enable
* register, to enable all interrupts for the device, this is the only bit * register, to enable all interrupts for the device, this is the only bit
...@@ -676,9 +681,13 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -676,9 +681,13 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__, dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__,
xiic_getreg8(i2c, XIIC_SR_REG_OFFSET)); xiic_getreg8(i2c, XIIC_SR_REG_OFFSET));
err = pm_runtime_get_sync(i2c->dev);
if (err < 0)
return err;
err = xiic_busy(i2c); err = xiic_busy(i2c);
if (err) if (err)
return err; goto out;
i2c->tx_msg = msgs; i2c->tx_msg = msgs;
i2c->nmsgs = num; i2c->nmsgs = num;
...@@ -686,14 +695,20 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -686,14 +695,20 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
xiic_start_xfer(i2c); xiic_start_xfer(i2c);
if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
(i2c->state == STATE_DONE), HZ)) (i2c->state == STATE_DONE), HZ)) {
return (i2c->state == STATE_DONE) ? num : -EIO; err = (i2c->state == STATE_DONE) ? num : -EIO;
else { goto out;
} else {
i2c->tx_msg = NULL; i2c->tx_msg = NULL;
i2c->rx_msg = NULL; i2c->rx_msg = NULL;
i2c->nmsgs = 0; i2c->nmsgs = 0;
return -ETIMEDOUT; err = -ETIMEDOUT;
goto out;
} }
out:
pm_runtime_mark_last_busy(i2c->dev);
pm_runtime_put_autosuspend(i2c->dev);
return err;
} }
static u32 xiic_func(struct i2c_adapter *adap) static u32 xiic_func(struct i2c_adapter *adap)
...@@ -748,13 +763,28 @@ static int xiic_i2c_probe(struct platform_device *pdev) ...@@ -748,13 +763,28 @@ static int xiic_i2c_probe(struct platform_device *pdev)
mutex_init(&i2c->lock); mutex_init(&i2c->lock);
init_waitqueue_head(&i2c->wait); init_waitqueue_head(&i2c->wait);
i2c->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "input clock not found.\n");
return PTR_ERR(i2c->clk);
}
ret = clk_prepare_enable(i2c->clk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable clock.\n");
return ret;
}
i2c->dev = &pdev->dev;
pm_runtime_enable(i2c->dev);
pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT);
pm_runtime_use_autosuspend(i2c->dev);
pm_runtime_set_active(i2c->dev);
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr, ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
xiic_process, IRQF_ONESHOT, xiic_process, IRQF_ONESHOT,
pdev->name, i2c); pdev->name, i2c);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Cannot claim IRQ\n"); dev_err(&pdev->dev, "Cannot claim IRQ\n");
return ret; goto err_clk_dis;
} }
/* /*
...@@ -776,7 +806,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) ...@@ -776,7 +806,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to add adapter\n"); dev_err(&pdev->dev, "Failed to add adapter\n");
xiic_deinit(i2c); xiic_deinit(i2c);
return ret; goto err_clk_dis;
} }
if (pdata) { if (pdata) {
...@@ -786,16 +816,30 @@ static int xiic_i2c_probe(struct platform_device *pdev) ...@@ -786,16 +816,30 @@ static int xiic_i2c_probe(struct platform_device *pdev)
} }
return 0; return 0;
err_clk_dis:
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(i2c->clk);
return ret;
} }
static int xiic_i2c_remove(struct platform_device *pdev) static int xiic_i2c_remove(struct platform_device *pdev)
{ {
struct xiic_i2c *i2c = platform_get_drvdata(pdev); struct xiic_i2c *i2c = platform_get_drvdata(pdev);
int ret;
/* remove adapter & data */ /* remove adapter & data */
i2c_del_adapter(&i2c->adap); i2c_del_adapter(&i2c->adap);
ret = clk_prepare_enable(i2c->clk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable clock.\n");
return ret;
}
xiic_deinit(i2c); xiic_deinit(i2c);
clk_disable_unprepare(i2c->clk);
pm_runtime_disable(&pdev->dev);
return 0; return 0;
} }
...@@ -808,12 +852,42 @@ static const struct of_device_id xiic_of_match[] = { ...@@ -808,12 +852,42 @@ static const struct of_device_id xiic_of_match[] = {
MODULE_DEVICE_TABLE(of, xiic_of_match); MODULE_DEVICE_TABLE(of, xiic_of_match);
#endif #endif
static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xiic_i2c *i2c = platform_get_drvdata(pdev);
clk_disable(i2c->clk);
return 0;
}
static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xiic_i2c *i2c = platform_get_drvdata(pdev);
int ret;
ret = clk_enable(i2c->clk);
if (ret) {
dev_err(dev, "Cannot enable clock.\n");
return ret;
}
return 0;
}
static const struct dev_pm_ops xiic_dev_pm_ops = {
SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
cdns_i2c_runtime_resume, NULL)
};
static struct platform_driver xiic_i2c_driver = { static struct platform_driver xiic_i2c_driver = {
.probe = xiic_i2c_probe, .probe = xiic_i2c_probe,
.remove = xiic_i2c_remove, .remove = xiic_i2c_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = of_match_ptr(xiic_of_match), .of_match_table = of_match_ptr(xiic_of_match),
.pm = &xiic_dev_pm_ops,
}, },
}; };
......
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/slab.h>
#include "i2c-core.h" #include "i2c-core.h"
......
...@@ -28,32 +28,32 @@ ...@@ -28,32 +28,32 @@
*/ */
#include <dt-bindings/i2c/i2c.h> #include <dt-bindings/i2c/i2c.h>
#include <linux/module.h> #include <asm/uaccess.h>
#include <linux/kernel.h> #include <linux/acpi.h>
#include <linux/clk/clk-conf.h>
#include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/slab.h> #include <linux/hardirq.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/init.h>
#include <linux/irqflags.h>
#include <linux/jump_label.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/clk/clk-conf.h>
#include <linux/completion.h>
#include <linux/hardirq.h>
#include <linux/irqflags.h>
#include <linux/rwsem.h>
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h> #include <linux/pm_wakeirq.h>
#include <linux/acpi.h>
#include <linux/jump_label.h>
#include <asm/uaccess.h>
#include <linux/err.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include "i2c-core.h" #include "i2c-core.h"
...@@ -73,6 +73,7 @@ static struct device_type i2c_client_type; ...@@ -73,6 +73,7 @@ static struct device_type i2c_client_type;
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;
static bool is_registered;
void i2c_transfer_trace_reg(void) void i2c_transfer_trace_reg(void)
{ {
...@@ -1529,7 +1530,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1529,7 +1530,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
int res = 0; int res = 0;
/* Can't register until after driver model init */ /* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p))) { if (WARN_ON(!is_registered)) {
res = -EAGAIN; res = -EAGAIN;
goto out_list; goto out_list;
} }
...@@ -1926,7 +1927,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) ...@@ -1926,7 +1927,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
int res; int res;
/* Can't register until after driver model init */ /* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p))) if (WARN_ON(!is_registered))
return -EAGAIN; return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */ /* add the driver to the list of i2c drivers in the driver core */
...@@ -2104,6 +2105,9 @@ static int __init i2c_init(void) ...@@ -2104,6 +2105,9 @@ static int __init i2c_init(void)
retval = bus_register(&i2c_bus_type); retval = bus_register(&i2c_bus_type);
if (retval) if (retval)
return retval; return retval;
is_registered = true;
#ifdef CONFIG_I2C_COMPAT #ifdef CONFIG_I2C_COMPAT
i2c_adapter_compat_class = class_compat_register("i2c-adapter"); i2c_adapter_compat_class = class_compat_register("i2c-adapter");
if (!i2c_adapter_compat_class) { if (!i2c_adapter_compat_class) {
...@@ -2125,6 +2129,7 @@ static int __init i2c_init(void) ...@@ -2125,6 +2129,7 @@ static int __init i2c_init(void)
class_compat_unregister(i2c_adapter_compat_class); class_compat_unregister(i2c_adapter_compat_class);
bus_err: bus_err:
#endif #endif
is_registered = false;
bus_unregister(&i2c_bus_type); bus_unregister(&i2c_bus_type);
return retval; return retval;
} }
......
...@@ -22,17 +22,17 @@ ...@@ -22,17 +22,17 @@
/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */ /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/notifier.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h> #include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
/* /*
......
...@@ -19,13 +19,13 @@ ...@@ -19,13 +19,13 @@
* warranty of any kind, whether express or implied. * warranty of any kind, whether express or implied.
*/ */
#include <linux/kernel.h> #include <linux/acpi.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-mux.h> #include <linux/i2c-mux.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/acpi.h> #include <linux/slab.h>
/* multiplexer per channel data */ /* multiplexer per channel data */
struct i2c_mux_priv { struct i2c_mux_priv {
......
...@@ -15,14 +15,14 @@ ...@@ -15,14 +15,14 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-smbus.h> #include <linux/i2c-smbus.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h>
struct i2c_smbus_alert { struct i2c_smbus_alert {
unsigned int alert_edge_triggered:1; unsigned int alert_edge_triggered:1;
......
...@@ -17,13 +17,13 @@ ...@@ -17,13 +17,13 @@
#define DEBUG 1 #define DEBUG 1
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#define MAX_CHIPS 10 #define MAX_CHIPS 10
......
...@@ -72,4 +72,13 @@ config I2C_MUX_REG ...@@ -72,4 +72,13 @@ config I2C_MUX_REG
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-mux-reg. will be called i2c-mux-reg.
config I2C_DEMUX_PINCTRL
tristate "pinctrl-based I2C demultiplexer"
depends on PINCTRL && OF
select OF_DYNAMIC
help
If you say yes to this option, support will be included for an I2C
demultiplexer that uses the pinctrl subsystem. This is useful if you
want to change the I2C master at run-time depending on features.
endmenu endmenu
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
......
/*
* Pinctrl based I2C DeMultiplexer
*
* Copyright (C) 2015-16 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
* Copyright (C) 2015-16 by 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 as published by the
* Free Software Foundation; version 2 of the License.
*
* See the bindings doc for DTS setup and the sysfs doc for usage information.
* (look for filenames containing 'i2c-demux-pinctrl' in Documentation/)
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
struct i2c_demux_pinctrl_chan {
struct device_node *parent_np;
struct i2c_adapter *parent_adap;
struct of_changeset chgset;
};
struct i2c_demux_pinctrl_priv {
int cur_chan;
int num_chan;
struct device *dev;
const char *bus_name;
struct i2c_adapter cur_adap;
struct i2c_algorithm algo;
struct i2c_demux_pinctrl_chan chan[];
};
static struct property status_okay = { .name = "status", .length = 3, .value = "ok" };
static int i2c_demux_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct i2c_demux_pinctrl_priv *priv = adap->algo_data;
struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap;
return __i2c_transfer(parent, msgs, num);
}
static u32 i2c_demux_functionality(struct i2c_adapter *adap)
{
struct i2c_demux_pinctrl_priv *priv = adap->algo_data;
struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap;
return parent->algo->functionality(parent);
}
static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 new_chan)
{
struct i2c_adapter *adap;
struct pinctrl *p;
int ret;
ret = of_changeset_apply(&priv->chan[new_chan].chgset);
if (ret)
goto err;
adap = of_find_i2c_adapter_by_node(priv->chan[new_chan].parent_np);
if (!adap) {
ret = -ENODEV;
goto err;
}
p = devm_pinctrl_get_select(adap->dev.parent, priv->bus_name);
if (IS_ERR(p)) {
ret = PTR_ERR(p);
goto err_with_put;
}
priv->chan[new_chan].parent_adap = adap;
priv->cur_chan = new_chan;
/* Now fill out current adapter structure. cur_chan must be up to date */
priv->algo.master_xfer = i2c_demux_master_xfer;
priv->algo.functionality = i2c_demux_functionality;
snprintf(priv->cur_adap.name, sizeof(priv->cur_adap.name),
"i2c-demux (master i2c-%d)", i2c_adapter_id(adap));
priv->cur_adap.owner = THIS_MODULE;
priv->cur_adap.algo = &priv->algo;
priv->cur_adap.algo_data = priv;
priv->cur_adap.dev.parent = priv->dev;
priv->cur_adap.class = adap->class;
priv->cur_adap.retries = adap->retries;
priv->cur_adap.timeout = adap->timeout;
priv->cur_adap.quirks = adap->quirks;
priv->cur_adap.dev.of_node = priv->dev->of_node;
ret = i2c_add_adapter(&priv->cur_adap);
if (ret < 0)
goto err_with_put;
return 0;
err_with_put:
i2c_put_adapter(adap);
err:
dev_err(priv->dev, "failed to setup demux-adapter %d (%d)\n", new_chan, ret);
return ret;
}
static int i2c_demux_deactivate_master(struct i2c_demux_pinctrl_priv *priv)
{
int ret, cur = priv->cur_chan;
if (cur < 0)
return 0;
i2c_del_adapter(&priv->cur_adap);
i2c_put_adapter(priv->chan[cur].parent_adap);
ret = of_changeset_revert(&priv->chan[cur].chgset);
priv->chan[cur].parent_adap = NULL;
priv->cur_chan = -EINVAL;
return ret;
}
static int i2c_demux_change_master(struct i2c_demux_pinctrl_priv *priv, u32 new_chan)
{
int ret;
if (new_chan == priv->cur_chan)
return 0;
ret = i2c_demux_deactivate_master(priv);
if (ret)
return ret;
return i2c_demux_activate_master(priv, new_chan);
}
static ssize_t cur_master_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_demux_pinctrl_priv *priv = dev_get_drvdata(dev);
int count = 0, i;
for (i = 0; i < priv->num_chan && count < PAGE_SIZE; i++)
count += scnprintf(buf + count, PAGE_SIZE - count, "%c %d - %s\n",
i == priv->cur_chan ? '*' : ' ', i,
priv->chan[i].parent_np->full_name);
return count;
}
static ssize_t cur_master_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_demux_pinctrl_priv *priv = dev_get_drvdata(dev);
unsigned int val;
int ret;
ret = kstrtouint(buf, 0, &val);
if (ret < 0)
return ret;
if (val >= priv->num_chan)
return -EINVAL;
ret = i2c_demux_change_master(priv, val);
return ret < 0 ? ret : count;
}
static DEVICE_ATTR_RW(cur_master);
static int i2c_demux_pinctrl_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct i2c_demux_pinctrl_priv *priv;
int num_chan, i, j, err;
num_chan = of_count_phandle_with_args(np, "i2c-parent", NULL);
if (num_chan < 2) {
dev_err(&pdev->dev, "Need at least two I2C masters to switch\n");
return -EINVAL;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv)
+ num_chan * sizeof(struct i2c_demux_pinctrl_chan), GFP_KERNEL);
if (!priv)
return -ENOMEM;
err = of_property_read_string(np, "i2c-bus-name", &priv->bus_name);
if (err)
return err;
for (i = 0; i < num_chan; i++) {
struct device_node *adap_np;
adap_np = of_parse_phandle(np, "i2c-parent", i);
if (!adap_np) {
dev_err(&pdev->dev, "can't get phandle for parent %d\n", i);
err = -ENOENT;
goto err_rollback;
}
priv->chan[i].parent_np = adap_np;
of_changeset_init(&priv->chan[i].chgset);
of_changeset_update_property(&priv->chan[i].chgset, adap_np, &status_okay);
}
priv->num_chan = num_chan;
priv->dev = &pdev->dev;
platform_set_drvdata(pdev, priv);
/* switch to first parent as active master */
i2c_demux_activate_master(priv, 0);
err = device_create_file(&pdev->dev, &dev_attr_cur_master);
if (err)
goto err_rollback;
return 0;
err_rollback:
for (j = 0; j < i; j++) {
of_node_put(priv->chan[j].parent_np);
of_changeset_destroy(&priv->chan[j].chgset);
}
return err;
}
static int i2c_demux_pinctrl_remove(struct platform_device *pdev)
{
struct i2c_demux_pinctrl_priv *priv = platform_get_drvdata(pdev);
int i;
device_remove_file(&pdev->dev, &dev_attr_cur_master);
i2c_demux_deactivate_master(priv);
for (i = 0; i < priv->num_chan; i++) {
of_node_put(priv->chan[i].parent_np);
of_changeset_destroy(&priv->chan[i].chgset);
}
return 0;
}
static const struct of_device_id i2c_demux_pinctrl_of_match[] = {
{ .compatible = "i2c-demux-pinctrl", },
{},
};
MODULE_DEVICE_TABLE(of, i2c_demux_pinctrl_of_match);
static struct platform_driver i2c_demux_pinctrl_driver = {
.driver = {
.name = "i2c-demux-pinctrl",
.of_match_table = i2c_demux_pinctrl_of_match,
},
.probe = i2c_demux_pinctrl_probe,
.remove = i2c_demux_pinctrl_remove,
};
module_platform_driver(i2c_demux_pinctrl_driver);
MODULE_DESCRIPTION("pinctrl-based I2C demux driver");
MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c-demux-pinctrl");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment