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");
......
This diff is collapsed.
...@@ -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);
......
This diff is collapsed.
...@@ -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