Commit 29532455 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull i2c updates from Wolfram Sang:
 "Summary:

   - legacy PM code removed from the core, there were no users anymore
     (thanks to Lars-Peter Clausen)

   - new driver for Broadcom iProc

   - bigger driver updates for designware, rk3x, cadence, ocores

   - a bunch of smaller updates and bugfixes"

* 'i2c/for-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (31 commits)
  i2c: ocores: rework clk code to handle NULL cookie
  i2c: designware-baytrail: another fixup for proper Kconfig dependencies
  i2c: fix reference to functionality constants definition
  i2c: iproc: Add Broadcom iProc I2C Driver
  i2c: designware-pci: update Intel copyright line
  i2c: ocores: add common clock support
  i2c: hix5hd2: add COMPILE_TEST
  i2c: clarify comments about the dev_released completion
  i2c: ocores: fix clock-frequency binding usage
  i2c: tegra: Maintain CPU endianness
  i2c: designware-baytrail: use proper Kconfig dependencies
  i2c: designware: Do not calculate SCL timing parameters needlessly
  i2c: do not try to load modules for of-registered devices
  i2c: designware: Add Intel Baytrail PMIC I2C bus support
  i2c: designware: Add i2c bus locking support
  of: i2c: Add i2c-mux-idle-disconnect DT property to PCA954x mux driver
  i2c: designware: use {readl|writel}_relaxed instead of readl/writel
  i2c: designware-pci: no need to provide clk_khz
  i2c: designware-pci: remove Moorestown support
  i2c: imx: whitespace and checkpatch cleanup
  ...
parents 18a8d499 0d8fb599
Broadcom iProc I2C controller
Required properties:
- compatible:
Must be "brcm,iproc-i2c"
- reg:
Define the base and range of the I/O address space that contain the iProc
I2C controller registers
- interrupts:
Should contain the I2C interrupt
- clock-frequency:
This is the I2C bus clock. Need to be either 100000 or 400000
- #address-cells:
Always 1 (for I2C addresses)
- #size-cells:
Always 0
Example:
i2c0: i2c@18008000 {
compatible = "brcm,iproc-i2c";
reg = <0x18008000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
clock-frequency = <100000>;
codec: wm8750@1a {
compatible = "wlf,wm8750";
reg = <0x1a>;
};
};
...@@ -16,6 +16,9 @@ Required Properties: ...@@ -16,6 +16,9 @@ Required Properties:
Optional Properties: Optional Properties:
- reset-gpios: Reference to the GPIO connected to the reset input. - reset-gpios: Reference to the GPIO connected to the reset input.
- i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
children in idle state. This is necessary for example, if there are several
multiplexers on the bus and the devices behind them use same I2C addresses.
Example: Example:
......
...@@ -4,24 +4,60 @@ Required properties: ...@@ -4,24 +4,60 @@ Required properties:
- compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst" - compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
- reg : bus address start and address range size of device - reg : bus address start and address range size of device
- interrupts : interrupt number - interrupts : interrupt number
- clock-frequency : frequency of bus clock in Hz - clocks : handle to the controller clock; see the note below.
Mutually exclusive with opencores,ip-clock-frequency
- opencores,ip-clock-frequency: frequency of the controller clock in Hz;
see the note below. Mutually exclusive with clocks
- #address-cells : should be <1> - #address-cells : should be <1>
- #size-cells : should be <0> - #size-cells : should be <0>
Optional properties: Optional properties:
- clock-frequency : frequency of bus clock in Hz; see the note below.
Defaults to 100 KHz when the property is not specified
- reg-shift : device register offsets are shifted by this value - reg-shift : device register offsets are shifted by this value
- reg-io-width : io register width in bytes (1, 2 or 4) - reg-io-width : io register width in bytes (1, 2 or 4)
- regstep : deprecated, use reg-shift above - regstep : deprecated, use reg-shift above
Example: Note
clock-frequency property is meant to control the bus frequency for i2c bus
drivers, but it was incorrectly used to specify i2c controller input clock
frequency. So the following rules are set to fix this situation:
- if clock-frequency is present and neither opencores,ip-clock-frequency nor
clocks are, then clock-frequency specifies i2c controller clock frequency.
This is to keep backwards compatibility with setups using old DTB. i2c bus
frequency is fixed at 100 KHz.
- if clocks is present it specifies i2c controller clock. clock-frequency
property specifies i2c bus frequency.
- if opencores,ip-clock-frequency is present it specifies i2c controller
clock frequency. clock-frequency property specifies i2c bus frequency.
Examples:
i2c0: ocores@a0000000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "opencores,i2c-ocores";
reg = <0xa0000000 0x8>;
interrupts = <10>;
opencores,ip-clock-frequency = <20000000>;
reg-shift = <0>; /* 8 bit registers */
reg-io-width = <1>; /* 8 bit read/write */
dummy@60 {
compatible = "dummy";
reg = <0x60>;
};
};
or
i2c0: ocores@a0000000 { i2c0: ocores@a0000000 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
compatible = "opencores,i2c-ocores"; compatible = "opencores,i2c-ocores";
reg = <0xa0000000 0x8>; reg = <0xa0000000 0x8>;
interrupts = <10>; interrupts = <10>;
clock-frequency = <20000000>; clocks = <&osc>;
clock-frequency = <400000>; /* i2c bus frequency 400 KHz */
reg-shift = <0>; /* 8 bit registers */ reg-shift = <0>; /* 8 bit registers */
reg-io-width = <1>; /* 8 bit read/write */ reg-io-width = <1>; /* 8 bit read/write */
......
...@@ -21,6 +21,17 @@ Required on RK3066, RK3188 : ...@@ -21,6 +21,17 @@ Required on RK3066, RK3188 :
Optional properties : Optional properties :
- clock-frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used. - clock-frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used.
- i2c-scl-rising-time-ns : Number of nanoseconds the SCL signal takes to rise
(t(r) in I2C specification). If not specified this is assumed to be
the maximum the specification allows(1000 ns for Standard-mode,
300 ns for Fast-mode) which might cause slightly slower communication.
- i2c-scl-falling-time-ns : Number of nanoseconds the SCL signal takes to fall
(t(f) in the I2C specification). If not specified this is assumed to
be the maximum the specification allows (300 ns) which might cause
slightly slower communication.
- i2c-sda-falling-time-ns : Number of nanoseconds the SDA signal takes to fall
(t(f) in the I2C specification). If not specified we'll use the SCL
value since they are the same in nearly all cases.
Example: Example:
...@@ -39,4 +50,7 @@ i2c0: i2c@2002d000 { ...@@ -39,4 +50,7 @@ i2c0: i2c@2002d000 {
clock-names = "i2c"; clock-names = "i2c";
clocks = <&cru PCLK_I2C0>; clocks = <&cru PCLK_I2C0>;
i2c-scl-rising-time-ns = <800>;
i2c-scl-falling-time-ns = <100>;
}; };
...@@ -61,9 +61,8 @@ fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec ...@@ -61,9 +61,8 @@ fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz)
isl,isl12057 Intersil ISL12057 I2C RTC Chip isil,isl12057 Intersil ISL12057 I2C RTC Chip
isil,isl29028 (deprecated, use isl) isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor
isl,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
......
...@@ -12,7 +12,7 @@ FUNCTIONALITY CONSTANTS ...@@ -12,7 +12,7 @@ FUNCTIONALITY CONSTANTS
----------------------- -----------------------
For the most up-to-date list of functionality constants, please check For the most up-to-date list of functionality constants, please check
<linux/i2c.h>! <uapi/linux/i2c.h>!
I2C_FUNC_I2C Plain i2c-level commands (Pure SMBus I2C_FUNC_I2C Plain i2c-level commands (Pure SMBus
adapters typically can not do these) adapters typically can not do these)
......
...@@ -79,7 +79,7 @@ config I2C_AMD8111 ...@@ -79,7 +79,7 @@ config I2C_AMD8111
config I2C_HIX5HD2 config I2C_HIX5HD2
tristate "Hix5hd2 high-speed I2C driver" tristate "Hix5hd2 high-speed I2C driver"
depends on ARCH_HIX5HD2 depends on ARCH_HIX5HD2 || COMPILE_TEST
help help
Say Y here to include support for high-speed I2C controller in the Say Y here to include support for high-speed I2C controller in the
Hisilicon based hix5hd2 SoCs. Hisilicon based hix5hd2 SoCs.
...@@ -372,6 +372,16 @@ config I2C_BCM2835 ...@@ -372,6 +372,16 @@ config I2C_BCM2835
This support is also available as a module. If so, the module This support is also available as a module. If so, the module
will be called i2c-bcm2835. will be called i2c-bcm2835.
config I2C_BCM_IPROC
tristate "Broadcom iProc I2C controller"
depends on ARCH_BCM_IPROC || COMPILE_TEST
default ARCH_BCM_IPROC
help
If you say yes to this option, support will be included for the
Broadcom iProc I2C controller.
If you don't know what to do here, say N.
config I2C_BCM_KONA config I2C_BCM_KONA
tristate "BCM Kona I2C adapter" tristate "BCM Kona I2C adapter"
depends on ARCH_BCM_MOBILE depends on ARCH_BCM_MOBILE
...@@ -465,6 +475,16 @@ config I2C_DESIGNWARE_PCI ...@@ -465,6 +475,16 @@ config I2C_DESIGNWARE_PCI
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-designware-pci. will be called i2c-designware-pci.
config I2C_DESIGNWARE_BAYTRAIL
bool "Intel Baytrail I2C semaphore support"
depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI
help
This driver enables managed host access to the PMIC I2C bus on select
Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
the host to request uninterrupted access to the PMIC's I2C bus from
the platform firmware controlling it. You should say Y if running on
a BayTrail system using the AXP288.
config I2C_EFM32 config I2C_EFM32
tristate "EFM32 I2C controller" tristate "EFM32 I2C controller"
depends on ARCH_EFM32 || COMPILE_TEST depends on ARCH_EFM32 || COMPILE_TEST
......
...@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o ...@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
...@@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o ...@@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-platform-objs := i2c-designware-platdrv.o
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-pci-objs := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
......
/*
* Copyright (C) 2014 Broadcom 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define CFG_OFFSET 0x00
#define CFG_RESET_SHIFT 31
#define CFG_EN_SHIFT 30
#define CFG_M_RETRY_CNT_SHIFT 16
#define CFG_M_RETRY_CNT_MASK 0x0f
#define TIM_CFG_OFFSET 0x04
#define TIM_CFG_MODE_400_SHIFT 31
#define M_FIFO_CTRL_OFFSET 0x0c
#define M_FIFO_RX_FLUSH_SHIFT 31
#define M_FIFO_TX_FLUSH_SHIFT 30
#define M_FIFO_RX_CNT_SHIFT 16
#define M_FIFO_RX_CNT_MASK 0x7f
#define M_FIFO_RX_THLD_SHIFT 8
#define M_FIFO_RX_THLD_MASK 0x3f
#define M_CMD_OFFSET 0x30
#define M_CMD_START_BUSY_SHIFT 31
#define M_CMD_STATUS_SHIFT 25
#define M_CMD_STATUS_MASK 0x07
#define M_CMD_STATUS_SUCCESS 0x0
#define M_CMD_STATUS_LOST_ARB 0x1
#define M_CMD_STATUS_NACK_ADDR 0x2
#define M_CMD_STATUS_NACK_DATA 0x3
#define M_CMD_STATUS_TIMEOUT 0x4
#define M_CMD_PROTOCOL_SHIFT 9
#define M_CMD_PROTOCOL_MASK 0xf
#define M_CMD_PROTOCOL_BLK_WR 0x7
#define M_CMD_PROTOCOL_BLK_RD 0x8
#define M_CMD_PEC_SHIFT 8
#define M_CMD_RD_CNT_SHIFT 0
#define M_CMD_RD_CNT_MASK 0xff
#define IE_OFFSET 0x38
#define IE_M_RX_FIFO_FULL_SHIFT 31
#define IE_M_RX_THLD_SHIFT 30
#define IE_M_START_BUSY_SHIFT 28
#define IS_OFFSET 0x3c
#define IS_M_RX_FIFO_FULL_SHIFT 31
#define IS_M_RX_THLD_SHIFT 30
#define IS_M_START_BUSY_SHIFT 28
#define M_TX_OFFSET 0x40
#define M_TX_WR_STATUS_SHIFT 31
#define M_TX_DATA_SHIFT 0
#define M_TX_DATA_MASK 0xff
#define M_RX_OFFSET 0x44
#define M_RX_STATUS_SHIFT 30
#define M_RX_STATUS_MASK 0x03
#define M_RX_PEC_ERR_SHIFT 29
#define M_RX_DATA_SHIFT 0
#define M_RX_DATA_MASK 0xff
#define I2C_TIMEOUT_MESC 100
#define M_TX_RX_FIFO_SIZE 64
enum bus_speed_index {
I2C_SPD_100K = 0,
I2C_SPD_400K,
};
struct bcm_iproc_i2c_dev {
struct device *device;
int irq;
void __iomem *base;
struct i2c_adapter adapter;
struct completion done;
int xfer_is_done;
};
/*
* Can be expanded in the future if more interrupt status bits are utilized
*/
#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT)
static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
{
struct bcm_iproc_i2c_dev *iproc_i2c = data;
u32 status = readl(iproc_i2c->base + IS_OFFSET);
status &= ISR_MASK;
if (!status)
return IRQ_NONE;
writel(status, iproc_i2c->base + IS_OFFSET);
iproc_i2c->xfer_is_done = 1;
complete_all(&iproc_i2c->done);
return IRQ_HANDLED;
}
static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
struct i2c_msg *msg)
{
u32 val;
val = readl(iproc_i2c->base + M_CMD_OFFSET);
val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK;
switch (val) {
case M_CMD_STATUS_SUCCESS:
return 0;
case M_CMD_STATUS_LOST_ARB:
dev_dbg(iproc_i2c->device, "lost bus arbitration\n");
return -EAGAIN;
case M_CMD_STATUS_NACK_ADDR:
dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr);
return -ENXIO;
case M_CMD_STATUS_NACK_DATA:
dev_dbg(iproc_i2c->device, "NAK data\n");
return -ENXIO;
case M_CMD_STATUS_TIMEOUT:
dev_dbg(iproc_i2c->device, "bus timeout\n");
return -ETIMEDOUT;
default:
dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
return -EIO;
}
}
static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
struct i2c_msg *msg)
{
int ret, i;
u8 addr;
u32 val;
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
/* need to reserve one byte in the FIFO for the slave address */
if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
dev_err(iproc_i2c->device,
"only support data length up to %u bytes\n",
M_TX_RX_FIFO_SIZE - 1);
return -EOPNOTSUPP;
}
/* check if bus is busy */
if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
BIT(M_CMD_START_BUSY_SHIFT))) {
dev_warn(iproc_i2c->device, "bus is busy\n");
return -EBUSY;
}
/* format and load slave address into the TX FIFO */
addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
writel(addr, iproc_i2c->base + M_TX_OFFSET);
/* for a write transaction, load data into the TX FIFO */
if (!(msg->flags & I2C_M_RD)) {
for (i = 0; i < msg->len; i++) {
val = msg->buf[i];
/* mark the last byte */
if (i == msg->len - 1)
val |= 1 << M_TX_WR_STATUS_SHIFT;
writel(val, iproc_i2c->base + M_TX_OFFSET);
}
}
/* mark as incomplete before starting the transaction */
reinit_completion(&iproc_i2c->done);
iproc_i2c->xfer_is_done = 0;
/*
* Enable the "start busy" interrupt, which will be triggered after the
* transaction is done, i.e., the internal start_busy bit, transitions
* from 1 to 0.
*/
writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET);
/*
* Now we can activate the transfer. For a read operation, specify the
* number of bytes to read
*/
val = 1 << M_CMD_START_BUSY_SHIFT;
if (msg->flags & I2C_M_RD) {
val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
(msg->len << M_CMD_RD_CNT_SHIFT);
} else {
val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
}
writel(val, iproc_i2c->base + M_CMD_OFFSET);
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
/* disable all interrupts */
writel(0, iproc_i2c->base + IE_OFFSET);
/* read it back to flush the write */
readl(iproc_i2c->base + IE_OFFSET);
/* make sure the interrupt handler isn't running */
synchronize_irq(iproc_i2c->irq);
if (!time_left && !iproc_i2c->xfer_is_done) {
dev_err(iproc_i2c->device, "transaction timed out\n");
/* flush FIFOs */
val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
(1 << M_FIFO_TX_FLUSH_SHIFT);
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
return -ETIMEDOUT;
}
ret = bcm_iproc_i2c_check_status(iproc_i2c, msg);
if (ret) {
/* flush both TX/RX FIFOs */
val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
(1 << M_FIFO_TX_FLUSH_SHIFT);
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
return ret;
}
/*
* For a read operation, we now need to load the data from FIFO
* into the memory buffer
*/
if (msg->flags & I2C_M_RD) {
for (i = 0; i < msg->len; i++) {
msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >>
M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
}
}
return 0;
}
static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
struct i2c_msg msgs[], int num)
{
struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
int ret, i;
/* go through all messages */
for (i = 0; i < num; i++) {
ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]);
if (ret) {
dev_dbg(iproc_i2c->device, "xfer failed\n");
return ret;
}
}
return num;
}
static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm bcm_iproc_algo = {
.master_xfer = bcm_iproc_i2c_xfer,
.functionality = bcm_iproc_i2c_functionality,
};
static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
{
unsigned int bus_speed;
u32 val;
int ret = of_property_read_u32(iproc_i2c->device->of_node,
"clock-frequency", &bus_speed);
if (ret < 0) {
dev_info(iproc_i2c->device,
"unable to interpret clock-frequency DT property\n");
bus_speed = 100000;
}
if (bus_speed < 100000) {
dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n",
bus_speed);
dev_err(iproc_i2c->device,
"valid speeds are 100khz and 400khz\n");
return -EINVAL;
} else if (bus_speed < 400000) {
bus_speed = 100000;
} else {
bus_speed = 400000;
}
val = readl(iproc_i2c->base + TIM_CFG_OFFSET);
val &= ~(1 << TIM_CFG_MODE_400_SHIFT);
val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT;
writel(val, iproc_i2c->base + TIM_CFG_OFFSET);
dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed);
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)
{
int irq, ret = 0;
struct bcm_iproc_i2c_dev *iproc_i2c;
struct i2c_adapter *adap;
struct resource *res;
iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c),
GFP_KERNEL);
if (!iproc_i2c)
return -ENOMEM;
platform_set_drvdata(pdev, iproc_i2c);
iproc_i2c->device = &pdev->dev;
init_completion(&iproc_i2c->done);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res);
if (IS_ERR(iproc_i2c->base))
return PTR_ERR(iproc_i2c->base);
ret = bcm_iproc_i2c_init(iproc_i2c);
if (ret)
return ret;
ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
if (ret)
return ret;
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(iproc_i2c->device, "no irq resource\n");
return irq;
}
iproc_i2c->irq = irq;
ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0,
pdev->name, iproc_i2c);
if (ret < 0) {
dev_err(iproc_i2c->device, "unable to request irq %i\n", irq);
return ret;
}
bcm_iproc_i2c_enable_disable(iproc_i2c, true);
adap = &iproc_i2c->adapter;
i2c_set_adapdata(adap, iproc_i2c);
strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
adap->algo = &bcm_iproc_algo;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
ret = i2c_add_adapter(adap);
if (ret) {
dev_err(iproc_i2c->device, "failed to add adapter\n");
return ret;
}
return 0;
}
static int bcm_iproc_i2c_remove(struct platform_device *pdev)
{
struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
/* make sure there's no pending interrupt when we remove the adapter */
writel(0, iproc_i2c->base + IE_OFFSET);
readl(iproc_i2c->base + IE_OFFSET);
synchronize_irq(iproc_i2c->irq);
i2c_del_adapter(&iproc_i2c->adapter);
bcm_iproc_i2c_enable_disable(iproc_i2c, false);
return 0;
}
static const struct of_device_id bcm_iproc_i2c_of_match[] = {
{ .compatible = "brcm,iproc-i2c" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match);
static struct platform_driver bcm_iproc_i2c_driver = {
.driver = {
.name = "bcm-iproc-i2c",
.of_match_table = bcm_iproc_i2c_of_match,
},
.probe = bcm_iproc_i2c_probe,
.remove = bcm_iproc_i2c_remove,
};
module_platform_driver(bcm_iproc_i2c_driver);
MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
MODULE_DESCRIPTION("Broadcom iProc I2C Driver");
MODULE_LICENSE("GPL v2");
...@@ -128,6 +128,7 @@ ...@@ -128,6 +128,7 @@
* @suspended: Flag holding the device's PM status * @suspended: Flag holding the device's PM status
* @send_count: Number of bytes still expected to send * @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive * @recv_count: Number of bytes still expected to receive
* @curr_recv_count: Number of bytes to be received in current transfer
* @irq: IRQ number * @irq: IRQ number
* @input_clk: Input clock to I2C controller * @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed * @i2c_clk: Maximum I2C clock speed
...@@ -146,6 +147,7 @@ struct cdns_i2c { ...@@ -146,6 +147,7 @@ struct cdns_i2c {
u8 suspended; u8 suspended;
unsigned int send_count; unsigned int send_count;
unsigned int recv_count; unsigned int recv_count;
unsigned int curr_recv_count;
int irq; int irq;
unsigned long input_clk; unsigned long input_clk;
unsigned int i2c_clk; unsigned int i2c_clk;
...@@ -182,14 +184,15 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id) ...@@ -182,14 +184,15 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
*/ */
static irqreturn_t cdns_i2c_isr(int irq, void *ptr) static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
{ {
unsigned int isr_status, avail_bytes; unsigned int isr_status, avail_bytes, updatetx;
unsigned int bytes_to_recv, bytes_to_send; unsigned int bytes_to_send;
struct cdns_i2c *id = ptr; struct cdns_i2c *id = ptr;
/* Signal completion only after everything is updated */ /* Signal completion only after everything is updated */
int done_flag = 0; int done_flag = 0;
irqreturn_t status = IRQ_NONE; irqreturn_t status = IRQ_NONE;
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/* Handling nack and arbitration lost interrupt */ /* Handling nack and arbitration lost interrupt */
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) { if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
...@@ -197,47 +200,87 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) ...@@ -197,47 +200,87 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
status = IRQ_HANDLED; status = IRQ_HANDLED;
} }
/* Handling Data interrupt */ /*
if ((isr_status & CDNS_I2C_IXR_DATA) && * Check if transfer size register needs to be updated again for a
(id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) { * large data receive operation.
/* Always read data interrupt threshold bytes */ */
bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH; updatetx = 0;
id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH; if (id->recv_count > id->curr_recv_count)
avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); updatetx = 1;
/* When receiving, handle data interrupt and completion interrupt */
if (id->p_recv_buf &&
((isr_status & CDNS_I2C_IXR_COMP) ||
(isr_status & CDNS_I2C_IXR_DATA))) {
/* Read data if receive data valid is set */
while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
CDNS_I2C_SR_RXDV) {
/*
* Clear hold bit that was set for FIFO control if
* RX data left is less than FIFO depth, unless
* repeated start is selected.
*/
if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) &&
!id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
*(id->p_recv_buf)++ =
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
id->recv_count--;
id->curr_recv_count--;
if (updatetx &&
(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1))
break;
}
/*
* The controller sends NACK to the slave when transfer size
* register reaches zero without considering the HOLD bit.
* This workaround is implemented for large data transfers to
* maintain transfer size non-zero while performing a large
* receive operation.
*/
if (updatetx &&
(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) {
/* wait while fifo is full */
while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
(id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
;
/* /*
* if the tranfer size register value is zero, then * Check number of bytes to be received against maximum
* check for the remaining bytes and update the * transfer size and update register accordingly.
* transfer size register.
*/ */
if (!avail_bytes) { if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) CDNS_I2C_TRANSFER_SIZE) {
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET); CDNS_I2C_XFER_SIZE_OFFSET);
else id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
cdns_i2c_writereg(id->recv_count, CDNS_I2C_FIFO_DEPTH;
} else {
cdns_i2c_writereg(id->recv_count -
CDNS_I2C_FIFO_DEPTH,
CDNS_I2C_XFER_SIZE_OFFSET); CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = id->recv_count;
}
} }
/* Process the data received */ /* Clear hold (if not repeated start) and signal completion */
while (bytes_to_recv--) if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
*(id->p_recv_buf)++ = if (!id->bus_hold_flag)
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
if (!id->bus_hold_flag &&
(id->recv_count <= CDNS_I2C_FIFO_DEPTH))
cdns_i2c_clear_bus_hold(id); cdns_i2c_clear_bus_hold(id);
done_flag = 1;
}
status = IRQ_HANDLED; status = IRQ_HANDLED;
} }
/* Handling Transfer Complete interrupt */ /* When sending, handle transfer complete interrupt */
if (isr_status & CDNS_I2C_IXR_COMP) { if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
if (!id->p_recv_buf) {
/* /*
* If the device is sending data If there is further * If there is more data to be sent, calculate the
* data to be sent. Calculate the available space * space available in FIFO and fill with that many bytes.
* in FIFO and fill the FIFO with that many bytes.
*/ */
if (id->send_count) { if (id->send_count) {
avail_bytes = CDNS_I2C_FIFO_DEPTH - avail_bytes = CDNS_I2C_FIFO_DEPTH -
...@@ -263,23 +306,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) ...@@ -263,23 +306,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
} }
if (!id->send_count && !id->bus_hold_flag) if (!id->send_count && !id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id); cdns_i2c_clear_bus_hold(id);
} else {
if (!id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
/*
* If the device is receiving data, then signal
* the completion of transaction and read the data
* present in the FIFO. Signal the completion of
* transaction.
*/
while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
CDNS_I2C_SR_RXDV) {
*(id->p_recv_buf)++ =
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
id->recv_count--;
}
done_flag = 1;
}
status = IRQ_HANDLED; status = IRQ_HANDLED;
} }
...@@ -289,8 +315,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) ...@@ -289,8 +315,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
if (id->err_status) if (id->err_status)
status = IRQ_HANDLED; status = IRQ_HANDLED;
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
if (done_flag) if (done_flag)
complete(&id->xfer_done); complete(&id->xfer_done);
...@@ -316,6 +340,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) ...@@ -316,6 +340,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
if (id->p_msg->flags & I2C_M_RECV_LEN) if (id->p_msg->flags & I2C_M_RECV_LEN)
id->recv_count = I2C_SMBUS_BLOCK_MAX + 1; id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
id->curr_recv_count = id->recv_count;
/* /*
* Check for the message size against FIFO depth and set the * Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth. * 'hold bus' bit if it is greater than FIFO depth.
...@@ -335,11 +361,14 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) ...@@ -335,11 +361,14 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
* receive if it is less than transfer size and transfer size if * receive if it is less than transfer size and transfer size if
* it is more. Enable the interrupts. * it is more. Enable the interrupts.
*/ */
if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET); CDNS_I2C_XFER_SIZE_OFFSET);
else id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
} else {
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET); cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
}
/* Clear the bus hold flag if bytes to receive is less than FIFO size */ /* Clear the bus hold flag if bytes to receive is less than FIFO size */
if (!id->bus_hold_flag && if (!id->bus_hold_flag &&
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
...@@ -516,6 +545,20 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -516,6 +545,20 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
* processed with a repeated start. * processed with a repeated start.
*/ */
if (num > 1) { if (num > 1) {
/*
* This controller does not give completion interrupt after a
* master receive message if HOLD bit is set (repeated start),
* resulting in SW timeout. Hence, if a receive message is
* followed by any other message, an error is returned
* indicating that this sequence is not supported.
*/
for (count = 0; count < num - 1; count++) {
if (msgs[count].flags & I2C_M_RD) {
dev_warn(adap->dev.parent,
"Can't do repeated start after a receive message\n");
return -EOPNOTSUPP;
}
}
id->bus_hold_flag = 1; id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD; reg |= CDNS_I2C_CR_HOLD;
......
/*
* Intel BayTrail PMIC I2C bus semaphore implementaion
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <asm/iosf_mbi.h>
#include "i2c-designware-core.h"
#define SEMAPHORE_TIMEOUT 100
#define PUNIT_SEMAPHORE 0x7
static unsigned long acquired;
static int get_sem(struct device *dev, u32 *sem)
{
u32 reg_val;
int ret;
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
&reg_val);
if (ret) {
dev_err(dev, "iosf failed to read punit semaphore\n");
return ret;
}
*sem = reg_val & 0x1;
return 0;
}
static void reset_semaphore(struct device *dev)
{
u32 data;
if (iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
PUNIT_SEMAPHORE, &data)) {
dev_err(dev, "iosf failed to reset punit semaphore during read\n");
return;
}
data = data & 0xfffffffe;
if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
PUNIT_SEMAPHORE, data))
dev_err(dev, "iosf failed to reset punit semaphore during write\n");
}
int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
{
u32 sem = 0;
int ret;
unsigned long start, end;
if (!dev || !dev->dev)
return -ENODEV;
if (!dev->acquire_lock)
return 0;
/* host driver writes 0x2 to side band semaphore register */
ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
PUNIT_SEMAPHORE, 0x2);
if (ret) {
dev_err(dev->dev, "iosf punit semaphore request failed\n");
return ret;
}
/* host driver waits for bit 0 to be set in semaphore register */
start = jiffies;
end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
while (!time_after(jiffies, end)) {
ret = get_sem(dev->dev, &sem);
if (!ret && sem) {
acquired = jiffies;
dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
jiffies_to_msecs(jiffies - start));
return 0;
}
usleep_range(1000, 2000);
}
dev_err(dev->dev, "punit semaphore timed out, resetting\n");
reset_semaphore(dev->dev);
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
PUNIT_SEMAPHORE, &sem);
if (!ret)
dev_err(dev->dev, "iosf failed to read punit semaphore\n");
else
dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
WARN_ON(1);
return -ETIMEDOUT;
}
EXPORT_SYMBOL(baytrail_i2c_acquire);
void baytrail_i2c_release(struct dw_i2c_dev *dev)
{
if (!dev || !dev->dev)
return;
if (!dev->acquire_lock)
return;
reset_semaphore(dev->dev);
dev_dbg(dev->dev, "punit semaphore held for %ums\n",
jiffies_to_msecs(jiffies - acquired));
}
EXPORT_SYMBOL(baytrail_i2c_release);
int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
{
acpi_status status;
unsigned long long shared_host = 0;
acpi_handle handle;
if (!dev || !dev->dev)
return 0;
handle = ACPI_HANDLE(dev->dev);
if (!handle)
return 0;
status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
if (ACPI_FAILURE(status))
return 0;
if (shared_host) {
dev_info(dev->dev, "I2C bus managed by PUNIT\n");
dev->acquire_lock = baytrail_i2c_acquire;
dev->release_lock = baytrail_i2c_release;
dev->pm_runtime_disabled = true;
}
if (!iosf_mbi_available())
return -EPROBE_DEFER;
return 0;
}
EXPORT_SYMBOL(i2c_dw_eval_lock_support);
MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
MODULE_LICENSE("GPL v2");
...@@ -170,10 +170,10 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset) ...@@ -170,10 +170,10 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
u32 value; u32 value;
if (dev->accessor_flags & ACCESS_16BIT) if (dev->accessor_flags & ACCESS_16BIT)
value = readw(dev->base + offset) | value = readw_relaxed(dev->base + offset) |
(readw(dev->base + offset + 2) << 16); (readw_relaxed(dev->base + offset + 2) << 16);
else else
value = readl(dev->base + offset); value = readl_relaxed(dev->base + offset);
if (dev->accessor_flags & ACCESS_SWAP) if (dev->accessor_flags & ACCESS_SWAP)
return swab32(value); return swab32(value);
...@@ -187,10 +187,10 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) ...@@ -187,10 +187,10 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
b = swab32(b); b = swab32(b);
if (dev->accessor_flags & ACCESS_16BIT) { if (dev->accessor_flags & ACCESS_16BIT) {
writew((u16)b, dev->base + offset); writew_relaxed((u16)b, dev->base + offset);
writew((u16)(b >> 16), dev->base + offset + 2); writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
} else { } else {
writel(b, dev->base + offset); writel_relaxed(b, dev->base + offset);
} }
} }
...@@ -285,6 +285,15 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -285,6 +285,15 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
u32 hcnt, lcnt; u32 hcnt, lcnt;
u32 reg; u32 reg;
u32 sda_falling_time, scl_falling_time; u32 sda_falling_time, scl_falling_time;
int ret;
if (dev->acquire_lock) {
ret = dev->acquire_lock(dev);
if (ret) {
dev_err(dev->dev, "couldn't acquire bus ownership\n");
return ret;
}
}
input_clock_khz = dev->get_clk_rate_khz(dev); input_clock_khz = dev->get_clk_rate_khz(dev);
...@@ -298,6 +307,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -298,6 +307,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
} else if (reg != DW_IC_COMP_TYPE_VALUE) { } else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev, "Unknown Synopsys component type: " dev_err(dev->dev, "Unknown Synopsys component type: "
"0x%08x\n", reg); "0x%08x\n", reg);
if (dev->release_lock)
dev->release_lock(dev);
return -ENODEV; return -ENODEV;
} }
...@@ -309,7 +320,11 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -309,7 +320,11 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
/* Standard-mode */ /* Set SCL timing parameters for standard-mode */
if (dev->ss_hcnt && dev->ss_lcnt) {
hcnt = dev->ss_hcnt;
lcnt = dev->ss_lcnt;
} else {
hcnt = i2c_dw_scl_hcnt(input_clock_khz, hcnt = i2c_dw_scl_hcnt(input_clock_khz,
4000, /* tHD;STA = tHIGH = 4.0 us */ 4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time, sda_falling_time,
...@@ -319,17 +334,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -319,17 +334,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
4700, /* tLOW = 4.7 us */ 4700, /* tLOW = 4.7 us */
scl_falling_time, scl_falling_time,
0); /* No offset */ 0); /* No offset */
/* Allow platforms to specify the ideal HCNT and LCNT values */
if (dev->ss_hcnt && dev->ss_lcnt) {
hcnt = dev->ss_hcnt;
lcnt = dev->ss_lcnt;
} }
dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
/* Fast-mode */ /* Set SCL timing parameters for fast-mode */
if (dev->fs_hcnt && dev->fs_lcnt) {
hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt;
} else {
hcnt = i2c_dw_scl_hcnt(input_clock_khz, hcnt = i2c_dw_scl_hcnt(input_clock_khz,
600, /* tHD;STA = tHIGH = 0.6 us */ 600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time, sda_falling_time,
...@@ -339,10 +353,6 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -339,10 +353,6 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
1300, /* tLOW = 1.3 us */ 1300, /* tLOW = 1.3 us */
scl_falling_time, scl_falling_time,
0); /* No offset */ 0); /* No offset */
if (dev->fs_hcnt && dev->fs_lcnt) {
hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt;
} }
dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
...@@ -364,6 +374,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -364,6 +374,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
/* configure the i2c master */ /* configure the i2c master */
dw_writel(dev, dev->master_cfg , DW_IC_CON); dw_writel(dev, dev->master_cfg , DW_IC_CON);
if (dev->release_lock)
dev->release_lock(dev);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(i2c_dw_init); EXPORT_SYMBOL_GPL(i2c_dw_init);
...@@ -627,6 +640,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -627,6 +640,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev->abort_source = 0; dev->abort_source = 0;
dev->rx_outstanding = 0; dev->rx_outstanding = 0;
if (dev->acquire_lock) {
ret = dev->acquire_lock(dev);
if (ret) {
dev_err(dev->dev, "couldn't acquire bus ownership\n");
goto done_nolock;
}
}
ret = i2c_dw_wait_bus_not_busy(dev); ret = i2c_dw_wait_bus_not_busy(dev);
if (ret < 0) if (ret < 0)
goto done; goto done;
...@@ -672,6 +693,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -672,6 +693,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
ret = -EIO; ret = -EIO;
done: done:
if (dev->release_lock)
dev->release_lock(dev);
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); mutex_unlock(&dev->lock);
......
...@@ -61,6 +61,9 @@ ...@@ -61,6 +61,9 @@
* @ss_lcnt: standard speed LCNT value * @ss_lcnt: standard speed LCNT value
* @fs_hcnt: fast speed HCNT value * @fs_hcnt: fast speed HCNT value
* @fs_lcnt: fast speed LCNT value * @fs_lcnt: fast speed LCNT value
* @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus
* @pm_runtime_disabled: true if pm runtime is disabled
* *
* HCNT and LCNT parameters can be used if the platform knows more accurate * HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency. * values than the one computed based only on the input clock frequency.
...@@ -101,6 +104,9 @@ struct dw_i2c_dev { ...@@ -101,6 +104,9 @@ struct dw_i2c_dev {
u16 ss_lcnt; u16 ss_lcnt;
u16 fs_hcnt; u16 fs_hcnt;
u16 fs_lcnt; u16 fs_lcnt;
int (*acquire_lock)(struct dw_i2c_dev *dev);
void (*release_lock)(struct dw_i2c_dev *dev);
bool pm_runtime_disabled;
}; };
#define ACCESS_SWAP 0x00000001 #define ACCESS_SWAP 0x00000001
...@@ -119,3 +125,9 @@ extern void i2c_dw_disable(struct dw_i2c_dev *dev); ...@@ -119,3 +125,9 @@ extern void i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_clear_int(struct dw_i2c_dev *dev); extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
extern void i2c_dw_disable_int(struct dw_i2c_dev *dev); extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
#else
static inline int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) { return 0; }
#endif
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2009 Provigent Ltd.
* Copyright (C) 2011 Intel corporation. * Copyright (C) 2011, 2015 Intel Corporation.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
...@@ -40,10 +40,6 @@ ...@@ -40,10 +40,6 @@
#define DRIVER_NAME "i2c-designware-pci" #define DRIVER_NAME "i2c-designware-pci"
enum dw_pci_ctl_id_t { enum dw_pci_ctl_id_t {
moorestown_0,
moorestown_1,
moorestown_2,
medfield_0, medfield_0,
medfield_1, medfield_1,
medfield_2, medfield_2,
...@@ -102,27 +98,6 @@ static struct dw_scl_sda_cfg hsw_config = { ...@@ -102,27 +98,6 @@ static struct dw_scl_sda_cfg hsw_config = {
}; };
static struct dw_pci_controller dw_pci_controllers[] = { static struct dw_pci_controller dw_pci_controllers[] = {
[moorestown_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[moorestown_1] = {
.bus_num = 1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[moorestown_2] = {
.bus_num = 2,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_0] = { [medfield_0] = {
.bus_num = 0, .bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
...@@ -170,7 +145,6 @@ static struct dw_pci_controller dw_pci_controllers[] = { ...@@ -170,7 +145,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32, .tx_fifo_depth = 32,
.rx_fifo_depth = 32, .rx_fifo_depth = 32,
.clk_khz = 100000,
.functionality = I2C_FUNC_10BIT_ADDR, .functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &byt_config, .scl_sda_cfg = &byt_config,
}, },
...@@ -179,7 +153,6 @@ static struct dw_pci_controller dw_pci_controllers[] = { ...@@ -179,7 +153,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32, .tx_fifo_depth = 32,
.rx_fifo_depth = 32, .rx_fifo_depth = 32,
.clk_khz = 100000,
.functionality = I2C_FUNC_10BIT_ADDR, .functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &hsw_config, .scl_sda_cfg = &hsw_config,
}, },
...@@ -325,12 +298,8 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev) ...@@ -325,12 +298,8 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
MODULE_ALIAS("i2c_designware-pci"); MODULE_ALIAS("i2c_designware-pci");
static const struct pci_device_id i2_designware_pci_ids[] = { static const struct pci_device_id i2_designware_pci_ids[] = {
/* Moorestown */
{ PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
{ PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
{ PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
/* Medfield */ /* Medfield */
{ PCI_VDEVICE(INTEL, 0x0817), medfield_3,}, { PCI_VDEVICE(INTEL, 0x0817), medfield_3 },
{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 }, { PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 }, { PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
...@@ -348,7 +317,7 @@ static const struct pci_device_id i2_designware_pci_ids[] = { ...@@ -348,7 +317,7 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9c61), haswell }, { PCI_VDEVICE(INTEL, 0x9c61), haswell },
{ PCI_VDEVICE(INTEL, 0x9c62), haswell }, { PCI_VDEVICE(INTEL, 0x9c62), haswell },
/* Braswell / Cherrytrail */ /* Braswell / Cherrytrail */
{ PCI_VDEVICE(INTEL, 0x22C1), baytrail,}, { PCI_VDEVICE(INTEL, 0x22C1), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C2), baytrail }, { PCI_VDEVICE(INTEL, 0x22C2), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C3), baytrail }, { PCI_VDEVICE(INTEL, 0x22C3), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C4), baytrail }, { PCI_VDEVICE(INTEL, 0x22C4), baytrail },
......
...@@ -195,6 +195,10 @@ static int dw_i2c_probe(struct platform_device *pdev) ...@@ -195,6 +195,10 @@ static int dw_i2c_probe(struct platform_device *pdev)
clk_freq = pdata->i2c_scl_freq; clk_freq = pdata->i2c_scl_freq;
} }
r = i2c_dw_eval_lock_support(dev);
if (r)
return r;
dev->functionality = dev->functionality =
I2C_FUNC_I2C | I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR | I2C_FUNC_10BIT_ADDR |
...@@ -257,10 +261,14 @@ static int dw_i2c_probe(struct platform_device *pdev) ...@@ -257,10 +261,14 @@ static int dw_i2c_probe(struct platform_device *pdev)
return r; return r;
} }
if (dev->pm_runtime_disabled) {
pm_runtime_forbid(&pdev->dev);
} else {
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
}
return 0; return 0;
} }
...@@ -310,6 +318,8 @@ static int dw_i2c_resume(struct device *dev) ...@@ -310,6 +318,8 @@ static int dw_i2c_resume(struct device *dev)
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
clk_prepare_enable(i_dev->clk); clk_prepare_enable(i_dev->clk);
if (!i_dev->pm_runtime_disabled)
i2c_dw_init(i_dev); i2c_dw_init(i_dev);
return 0; return 0;
......
...@@ -295,7 +295,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, ...@@ -295,7 +295,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma->chan_tx = dma_request_slave_channel(dev, "tx"); dma->chan_tx = dma_request_slave_channel(dev, "tx");
if (!dma->chan_tx) { if (!dma->chan_tx) {
dev_dbg(dev, "can't request DMA tx channel\n"); dev_dbg(dev, "can't request DMA tx channel\n");
ret = -ENODEV;
goto fail_al; goto fail_al;
} }
...@@ -313,7 +312,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, ...@@ -313,7 +312,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma->chan_rx = dma_request_slave_channel(dev, "rx"); dma->chan_rx = dma_request_slave_channel(dev, "rx");
if (!dma->chan_rx) { if (!dma->chan_rx) {
dev_dbg(dev, "can't request DMA rx channel\n"); dev_dbg(dev, "can't request DMA rx channel\n");
ret = -ENODEV;
goto fail_tx; goto fail_tx;
} }
...@@ -481,7 +479,7 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) ...@@ -481,7 +479,7 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
i2c_clk_rate = clk_get_rate(i2c_imx->clk); i2c_clk_rate = clk_get_rate(i2c_imx->clk);
if (i2c_imx->cur_clk == i2c_clk_rate) if (i2c_imx->cur_clk == i2c_clk_rate)
return; return;
else
i2c_imx->cur_clk = i2c_clk_rate; i2c_imx->cur_clk = i2c_clk_rate;
div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate; div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate;
...@@ -490,7 +488,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) ...@@ -490,7 +488,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
i = i2c_imx->hwdata->ndivs - 1; i = i2c_imx->hwdata->ndivs - 1;
else else
for (i = 0; i2c_clk_div[i].div < div; i++); for (i = 0; i2c_clk_div[i].div < div; i++)
;
/* Store divider value */ /* Store divider value */
i2c_imx->ifdr = i2c_clk_div[i].val; i2c_imx->ifdr = i2c_clk_div[i].val;
...@@ -628,9 +627,9 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, ...@@ -628,9 +627,9 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
result = wait_for_completion_timeout( result = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete, &i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT)); msecs_to_jiffies(DMA_TIMEOUT));
if (result <= 0) { if (result == 0) {
dmaengine_terminate_all(dma->chan_using); dmaengine_terminate_all(dma->chan_using);
return result ?: -ETIMEDOUT; return -ETIMEDOUT;
} }
/* Waiting for transfer complete. */ /* Waiting for transfer complete. */
...@@ -686,9 +685,9 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, ...@@ -686,9 +685,9 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
result = wait_for_completion_timeout( result = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete, &i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT)); msecs_to_jiffies(DMA_TIMEOUT));
if (result <= 0) { if (result == 0) {
dmaengine_terminate_all(dma->chan_using); dmaengine_terminate_all(dma->chan_using);
return result ?: -ETIMEDOUT; return -ETIMEDOUT;
} }
/* waiting for transfer complete. */ /* waiting for transfer complete. */
...@@ -822,6 +821,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo ...@@ -822,6 +821,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
/* read data */ /* read data */
for (i = 0; i < msgs->len; i++) { for (i = 0; i < msgs->len; i++) {
u8 len = 0; u8 len = 0;
result = i2c_imx_trx_complete(i2c_imx); result = i2c_imx_trx_complete(i2c_imx);
if (result) if (result)
return result; return result;
...@@ -917,15 +917,16 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, ...@@ -917,15 +917,16 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
/* write/read data */ /* write/read data */
#ifdef CONFIG_I2C_DEBUG_BUS #ifdef CONFIG_I2C_DEBUG_BUS
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, " dev_dbg(&i2c_imx->adapter.dev,
"MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__, "<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",
__func__,
(temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0), (temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
(temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0), (temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
(temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0)); (temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
dev_dbg(&i2c_imx->adapter.dev, dev_dbg(&i2c_imx->adapter.dev,
"<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, " "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",
"IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__, __func__,
(temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0), (temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
(temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0), (temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0), (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
...@@ -1063,7 +1064,7 @@ static int i2c_imx_probe(struct platform_device *pdev) ...@@ -1063,7 +1064,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.name); i2c_imx->adapter.name);
dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
/* Init DMA config if support*/ /* Init DMA config if supported */
i2c_imx_dma_request(i2c_imx, phy_addr); i2c_imx_dma_request(i2c_imx, phy_addr);
return 0; /* Return OK */ return 0; /* Return OK */
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* kind, whether express or implied. * kind, whether express or implied.
*/ */
#include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -35,7 +36,9 @@ struct ocores_i2c { ...@@ -35,7 +36,9 @@ struct ocores_i2c {
int pos; int pos;
int nmsgs; int nmsgs;
int state; /* see STATE_ */ int state; /* see STATE_ */
int clock_khz; struct clk *clk;
int ip_clock_khz;
int bus_clock_khz;
void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value);
u8 (*getreg)(struct ocores_i2c *i2c, int reg); u8 (*getreg)(struct ocores_i2c *i2c, int reg);
}; };
...@@ -215,21 +218,34 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -215,21 +218,34 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void ocores_init(struct ocores_i2c *i2c) static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
{ {
int prescale; int prescale;
int diff;
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
/* make sure the device is disabled */ /* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
prescale = (i2c->clock_khz / (5*100)) - 1; prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1;
prescale = clamp(prescale, 0, 0xffff);
diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz;
if (abs(diff) > i2c->bus_clock_khz / 10) {
dev_err(dev,
"Unsupported clock settings: core: %d KHz, bus: %d KHz\n",
i2c->ip_clock_khz, i2c->bus_clock_khz);
return -EINVAL;
}
oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
/* Init the device */ /* Init the device */
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN); oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
return 0;
} }
...@@ -304,6 +320,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, ...@@ -304,6 +320,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match; const struct of_device_id *match;
u32 val; u32 val;
u32 clock_frequency;
bool clock_frequency_present;
if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
/* no 'reg-shift', check for deprecated 'regstep' */ /* no 'reg-shift', check for deprecated 'regstep' */
...@@ -319,12 +337,42 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, ...@@ -319,12 +337,42 @@ static int ocores_i2c_of_probe(struct platform_device *pdev,
} }
} }
if (of_property_read_u32(np, "clock-frequency", &val)) { clock_frequency_present = !of_property_read_u32(np, "clock-frequency",
&clock_frequency);
i2c->bus_clock_khz = 100;
i2c->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(i2c->clk)) {
int ret = clk_prepare_enable(i2c->clk);
if (ret) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Missing required parameter 'clock-frequency'\n"); "clk_prepare_enable failed: %d\n", ret);
return ret;
}
i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000;
if (clock_frequency_present)
i2c->bus_clock_khz = clock_frequency / 1000;
}
if (i2c->ip_clock_khz == 0) {
if (of_property_read_u32(np, "opencores,ip-clock-frequency",
&val)) {
if (!clock_frequency_present) {
dev_err(&pdev->dev,
"Missing required parameter 'opencores,ip-clock-frequency'\n");
return -ENODEV; return -ENODEV;
} }
i2c->clock_khz = val / 1000; i2c->ip_clock_khz = clock_frequency / 1000;
dev_warn(&pdev->dev,
"Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n");
} else {
i2c->ip_clock_khz = val / 1000;
if (clock_frequency_present)
i2c->bus_clock_khz = clock_frequency / 1000;
}
}
of_property_read_u32(pdev->dev.of_node, "reg-io-width", of_property_read_u32(pdev->dev.of_node, "reg-io-width",
&i2c->reg_io_width); &i2c->reg_io_width);
...@@ -368,7 +416,8 @@ static int ocores_i2c_probe(struct platform_device *pdev) ...@@ -368,7 +416,8 @@ static int ocores_i2c_probe(struct platform_device *pdev)
if (pdata) { if (pdata) {
i2c->reg_shift = pdata->reg_shift; i2c->reg_shift = pdata->reg_shift;
i2c->reg_io_width = pdata->reg_io_width; i2c->reg_io_width = pdata->reg_io_width;
i2c->clock_khz = pdata->clock_khz; i2c->ip_clock_khz = pdata->clock_khz;
i2c->bus_clock_khz = 100;
} else { } else {
ret = ocores_i2c_of_probe(pdev, i2c); ret = ocores_i2c_of_probe(pdev, i2c);
if (ret) if (ret)
...@@ -402,7 +451,9 @@ static int ocores_i2c_probe(struct platform_device *pdev) ...@@ -402,7 +451,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
} }
} }
ocores_init(i2c); ret = ocores_init(&pdev->dev, i2c);
if (ret)
return ret;
init_waitqueue_head(&i2c->wait); init_waitqueue_head(&i2c->wait);
ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
...@@ -446,6 +497,9 @@ static int ocores_i2c_remove(struct platform_device *pdev) ...@@ -446,6 +497,9 @@ static int ocores_i2c_remove(struct platform_device *pdev)
/* remove adapter & data */ /* remove adapter & data */
i2c_del_adapter(&i2c->adap); i2c_del_adapter(&i2c->adap);
if (!IS_ERR(i2c->clk))
clk_disable_unprepare(i2c->clk);
return 0; return 0;
} }
...@@ -458,6 +512,8 @@ static int ocores_i2c_suspend(struct device *dev) ...@@ -458,6 +512,8 @@ static int ocores_i2c_suspend(struct device *dev)
/* make sure the device is disabled */ /* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
if (!IS_ERR(i2c->clk))
clk_disable_unprepare(i2c->clk);
return 0; return 0;
} }
...@@ -465,9 +521,20 @@ static int ocores_i2c_resume(struct device *dev) ...@@ -465,9 +521,20 @@ static int ocores_i2c_resume(struct device *dev)
{ {
struct ocores_i2c *i2c = dev_get_drvdata(dev); struct ocores_i2c *i2c = dev_get_drvdata(dev);
ocores_init(i2c); if (!IS_ERR(i2c->clk)) {
unsigned long rate;
int ret = clk_prepare_enable(i2c->clk);
return 0; if (ret) {
dev_err(dev,
"clk_prepare_enable failed: %d\n", ret);
return ret;
}
rate = clk_get_rate(i2c->clk) / 1000;
if (rate)
i2c->ip_clock_khz = rate;
}
return ocores_init(dev, i2c);
} }
static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
......
...@@ -148,13 +148,6 @@ static inline u32 pmcmsptwi_clock_to_reg( ...@@ -148,13 +148,6 @@ static inline u32 pmcmsptwi_clock_to_reg(
return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff); return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
} }
static inline void pmcmsptwi_reg_to_clock(
u32 reg, struct pmcmsptwi_clock *clock)
{
clock->filter = (reg >> 12) & 0xf;
clock->clock = reg & 0x03ff;
}
static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg) static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
{ {
return ((cfg->arbf & 0xf) << 12) | return ((cfg->arbf & 0xf) << 12) |
......
...@@ -102,6 +102,9 @@ struct rk3x_i2c { ...@@ -102,6 +102,9 @@ struct rk3x_i2c {
/* Settings */ /* Settings */
unsigned int scl_frequency; unsigned int scl_frequency;
unsigned int scl_rise_ns;
unsigned int scl_fall_ns;
unsigned int sda_fall_ns;
/* Synchronization & notification */ /* Synchronization & notification */
spinlock_t lock; spinlock_t lock;
...@@ -435,6 +438,9 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) ...@@ -435,6 +438,9 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
* *
* @clk_rate: I2C input clock rate * @clk_rate: I2C input clock rate
* @scl_rate: Desired SCL rate * @scl_rate: Desired SCL rate
* @scl_rise_ns: How many ns it takes for SCL to rise.
* @scl_fall_ns: How many ns it takes for SCL to fall.
* @sda_fall_ns: How many ns it takes for SDA to fall.
* @div_low: Divider output for low * @div_low: Divider output for low
* @div_high: Divider output for high * @div_high: Divider output for high
* *
...@@ -443,11 +449,16 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) ...@@ -443,11 +449,16 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
* too high, we silently use the highest possible rate. * too high, we silently use the highest possible rate.
*/ */
static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
unsigned long scl_rise_ns,
unsigned long scl_fall_ns,
unsigned long sda_fall_ns,
unsigned long *div_low, unsigned long *div_high) unsigned long *div_low, unsigned long *div_high)
{ {
unsigned long min_low_ns, min_high_ns; unsigned long spec_min_low_ns, spec_min_high_ns;
unsigned long max_data_hold_ns; unsigned long spec_setup_start, spec_max_data_hold_ns;
unsigned long data_hold_buffer_ns; unsigned long data_hold_buffer_ns;
unsigned long min_low_ns, min_high_ns;
unsigned long max_low_ns, min_total_ns; unsigned long max_low_ns, min_total_ns;
unsigned long clk_rate_khz, scl_rate_khz; unsigned long clk_rate_khz, scl_rate_khz;
...@@ -469,29 +480,50 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, ...@@ -469,29 +480,50 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
scl_rate = 1000; scl_rate = 1000;
/* /*
* min_low_ns: The minimum number of ns we need to hold low * min_low_ns: The minimum number of ns we need to hold low to
* to meet i2c spec * meet I2C specification, should include fall time.
* min_high_ns: The minimum number of ns we need to hold high * min_high_ns: The minimum number of ns we need to hold high to
* to meet i2c spec * meet I2C specification, should include rise time.
* max_low_ns: The maximum number of ns we can hold low * max_low_ns: The maximum number of ns we can hold low to meet
* to meet i2c spec * I2C specification.
* *
* Note: max_low_ns should be (max data hold time * 2 - buffer) * Note: max_low_ns should be (maximum data hold time * 2 - buffer)
* This is because the i2c host on Rockchip holds the data line * This is because the i2c host on Rockchip holds the data line
* for half the low time. * for half the low time.
*/ */
if (scl_rate <= 100000) { if (scl_rate <= 100000) {
min_low_ns = 4700; /* Standard-mode */
min_high_ns = 4000; spec_min_low_ns = 4700;
max_data_hold_ns = 3450; spec_setup_start = 4700;
spec_min_high_ns = 4000;
spec_max_data_hold_ns = 3450;
data_hold_buffer_ns = 50; data_hold_buffer_ns = 50;
} else { } else {
min_low_ns = 1300; /* Fast-mode */
min_high_ns = 600; spec_min_low_ns = 1300;
max_data_hold_ns = 900; spec_setup_start = 600;
spec_min_high_ns = 600;
spec_max_data_hold_ns = 900;
data_hold_buffer_ns = 50; data_hold_buffer_ns = 50;
} }
max_low_ns = max_data_hold_ns * 2 - data_hold_buffer_ns; min_high_ns = scl_rise_ns + spec_min_high_ns;
/*
* Timings for repeated start:
* - controller appears to drop SDA at .875x (7/8) programmed clk high.
* - controller appears to keep SCL high for 2x programmed clk high.
*
* We need to account for those rules in picking our "high" time so
* we meet tSU;STA and tHD;STA times.
*/
min_high_ns = max(min_high_ns,
DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875));
min_high_ns = max(min_high_ns,
DIV_ROUND_UP((scl_rise_ns + spec_setup_start +
sda_fall_ns + spec_min_high_ns), 2));
min_low_ns = scl_fall_ns + spec_min_low_ns;
max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns; min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */ /* Adjust to avoid overflow */
...@@ -510,8 +542,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, ...@@ -510,8 +542,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
min_div_for_hold = (min_low_div + min_high_div); min_div_for_hold = (min_low_div + min_high_div);
/* /*
* This is the maximum divider so we don't go over the max. * This is the maximum divider so we don't go over the maximum.
* We don't round up here (we round down) since this is a max. * We don't round up here (we round down) since this is a maximum.
*/ */
max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000); max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
...@@ -544,7 +576,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, ...@@ -544,7 +576,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
scl_rate_khz * 8 * min_total_ns); scl_rate_khz * 8 * min_total_ns);
/* Don't allow it to go over the max */ /* Don't allow it to go over the maximum */
if (ideal_low_div > max_low_div) if (ideal_low_div > max_low_div)
ideal_low_div = max_low_div; ideal_low_div = max_low_div;
...@@ -588,9 +620,9 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) ...@@ -588,9 +620,9 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
u64 t_low_ns, t_high_ns; u64 t_low_ns, t_high_ns;
int ret; int ret;
ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, &div_low, ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns,
&div_high); i2c->scl_fall_ns, i2c->sda_fall_ns,
&div_low, &div_high);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency); WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
clk_enable(i2c->clk); clk_enable(i2c->clk);
...@@ -633,9 +665,10 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long ...@@ -633,9 +665,10 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
switch (event) { switch (event) {
case PRE_RATE_CHANGE: case PRE_RATE_CHANGE:
if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency, if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
&div_low, &div_high) != 0) { i2c->scl_rise_ns, i2c->scl_fall_ns,
i2c->sda_fall_ns,
&div_low, &div_high) != 0)
return NOTIFY_STOP; return NOTIFY_STOP;
}
/* scale up */ /* scale up */
if (ndata->new_rate > ndata->old_rate) if (ndata->new_rate > ndata->old_rate)
...@@ -859,6 +892,24 @@ static int rk3x_i2c_probe(struct platform_device *pdev) ...@@ -859,6 +892,24 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
i2c->scl_frequency = DEFAULT_SCL_RATE; i2c->scl_frequency = DEFAULT_SCL_RATE;
} }
/*
* Read rise and fall time from device tree. If not available use
* the default maximum timing from the specification.
*/
if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns",
&i2c->scl_rise_ns)) {
if (i2c->scl_frequency <= 100000)
i2c->scl_rise_ns = 1000;
else
i2c->scl_rise_ns = 300;
}
if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns",
&i2c->scl_fall_ns))
i2c->scl_fall_ns = 300;
if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
&i2c->scl_fall_ns))
i2c->sda_fall_ns = i2c->scl_fall_ns;
strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE; i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &rk3x_i2c_algorithm; i2c->adap.algo = &rk3x_i2c_algorithm;
......
...@@ -286,6 +286,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) ...@@ -286,6 +286,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
if (rx_fifo_avail > 0 && buf_remaining > 0) { if (rx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3); BUG_ON(buf_remaining > 3);
val = i2c_readl(i2c_dev, I2C_RX_FIFO); val = i2c_readl(i2c_dev, I2C_RX_FIFO);
val = cpu_to_le32(val);
memcpy(buf, &val, buf_remaining); memcpy(buf, &val, buf_remaining);
buf_remaining = 0; buf_remaining = 0;
rx_fifo_avail--; rx_fifo_avail--;
...@@ -344,6 +345,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) ...@@ -344,6 +345,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
if (tx_fifo_avail > 0 && buf_remaining > 0) { if (tx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3); BUG_ON(buf_remaining > 3);
memcpy(&val, buf, buf_remaining); memcpy(&val, buf, buf_remaining);
val = le32_to_cpu(val);
/* Again update before writing to FIFO to make sure isr sees. */ /* Again update before writing to FIFO to make sure isr sees. */
i2c_dev->msg_buf_remaining = 0; i2c_dev->msg_buf_remaining = 0;
......
...@@ -102,7 +102,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) ...@@ -102,7 +102,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
struct acpi_resource_i2c_serialbus *sb; struct acpi_resource_i2c_serialbus *sb;
sb = &ares->data.i2c_serial_bus; sb = &ares->data.i2c_serial_bus;
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
info->addr = sb->slave_address; info->addr = sb->slave_address;
if (sb->access_mode == ACPI_I2C_10BIT_MODE) if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN; info->flags |= I2C_CLIENT_TEN;
...@@ -698,101 +698,6 @@ static void i2c_device_shutdown(struct device *dev) ...@@ -698,101 +698,6 @@ static void i2c_device_shutdown(struct device *dev)
driver->shutdown(client); driver->shutdown(client);
} }
#ifdef CONFIG_PM_SLEEP
static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client || !dev->driver)
return 0;
driver = to_i2c_driver(dev->driver);
if (!driver->suspend)
return 0;
return driver->suspend(client, mesg);
}
static int i2c_legacy_resume(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client || !dev->driver)
return 0;
driver = to_i2c_driver(dev->driver);
if (!driver->resume)
return 0;
return driver->resume(client);
}
static int i2c_device_pm_suspend(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm)
return pm_generic_suspend(dev);
else
return i2c_legacy_suspend(dev, PMSG_SUSPEND);
}
static int i2c_device_pm_resume(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm)
return pm_generic_resume(dev);
else
return i2c_legacy_resume(dev);
}
static int i2c_device_pm_freeze(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm)
return pm_generic_freeze(dev);
else
return i2c_legacy_suspend(dev, PMSG_FREEZE);
}
static int i2c_device_pm_thaw(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm)
return pm_generic_thaw(dev);
else
return i2c_legacy_resume(dev);
}
static int i2c_device_pm_poweroff(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm)
return pm_generic_poweroff(dev);
else
return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
}
static int i2c_device_pm_restore(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm)
return pm_generic_restore(dev);
else
return i2c_legacy_resume(dev);
}
#else /* !CONFIG_PM_SLEEP */
#define i2c_device_pm_suspend NULL
#define i2c_device_pm_resume NULL
#define i2c_device_pm_freeze NULL
#define i2c_device_pm_thaw NULL
#define i2c_device_pm_poweroff NULL
#define i2c_device_pm_restore NULL
#endif /* !CONFIG_PM_SLEEP */
static void i2c_client_dev_release(struct device *dev) static void i2c_client_dev_release(struct device *dev)
{ {
kfree(to_i2c_client(dev)); kfree(to_i2c_client(dev));
...@@ -804,6 +709,7 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf) ...@@ -804,6 +709,7 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", dev->type == &i2c_client_type ? return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
to_i2c_client(dev)->name : to_i2c_adapter(dev)->name); to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
} }
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static ssize_t static ssize_t
show_modalias(struct device *dev, struct device_attribute *attr, char *buf) show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
...@@ -817,8 +723,6 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf) ...@@ -817,8 +723,6 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
} }
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
static struct attribute *i2c_dev_attrs[] = { static struct attribute *i2c_dev_attrs[] = {
...@@ -827,29 +731,7 @@ static struct attribute *i2c_dev_attrs[] = { ...@@ -827,29 +731,7 @@ static struct attribute *i2c_dev_attrs[] = {
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
NULL NULL
}; };
ATTRIBUTE_GROUPS(i2c_dev);
static struct attribute_group i2c_dev_attr_group = {
.attrs = i2c_dev_attrs,
};
static const struct attribute_group *i2c_dev_attr_groups[] = {
&i2c_dev_attr_group,
NULL
};
static const struct dev_pm_ops i2c_device_pm_ops = {
.suspend = i2c_device_pm_suspend,
.resume = i2c_device_pm_resume,
.freeze = i2c_device_pm_freeze,
.thaw = i2c_device_pm_thaw,
.poweroff = i2c_device_pm_poweroff,
.restore = i2c_device_pm_restore,
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
NULL
)
};
struct bus_type i2c_bus_type = { struct bus_type i2c_bus_type = {
.name = "i2c", .name = "i2c",
...@@ -857,12 +739,11 @@ struct bus_type i2c_bus_type = { ...@@ -857,12 +739,11 @@ struct bus_type i2c_bus_type = {
.probe = i2c_device_probe, .probe = i2c_device_probe,
.remove = i2c_device_remove, .remove = i2c_device_remove,
.shutdown = i2c_device_shutdown, .shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
}; };
EXPORT_SYMBOL_GPL(i2c_bus_type); EXPORT_SYMBOL_GPL(i2c_bus_type);
static struct device_type i2c_client_type = { static struct device_type i2c_client_type = {
.groups = i2c_dev_attr_groups, .groups = i2c_dev_groups,
.uevent = i2c_device_uevent, .uevent = i2c_device_uevent,
.release = i2c_client_dev_release, .release = i2c_client_dev_release,
}; };
...@@ -1261,6 +1142,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, ...@@ -1261,6 +1142,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
return count; return count;
} }
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
/* /*
* And of course let the users delete the devices they instantiated, if * And of course let the users delete the devices they instantiated, if
...@@ -1315,8 +1197,6 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, ...@@ -1315,8 +1197,6 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
"delete_device"); "delete_device");
return res; return res;
} }
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL, static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
i2c_sysfs_delete_device); i2c_sysfs_delete_device);
...@@ -1326,18 +1206,10 @@ static struct attribute *i2c_adapter_attrs[] = { ...@@ -1326,18 +1206,10 @@ static struct attribute *i2c_adapter_attrs[] = {
&dev_attr_delete_device.attr, &dev_attr_delete_device.attr,
NULL NULL
}; };
ATTRIBUTE_GROUPS(i2c_adapter);
static struct attribute_group i2c_adapter_attr_group = {
.attrs = i2c_adapter_attrs,
};
static const struct attribute_group *i2c_adapter_attr_groups[] = {
&i2c_adapter_attr_group,
NULL
};
struct device_type i2c_adapter_type = { struct device_type i2c_adapter_type = {
.groups = i2c_adapter_attr_groups, .groups = i2c_adapter_groups,
.release = i2c_adapter_dev_release, .release = i2c_adapter_dev_release,
}; };
EXPORT_SYMBOL_GPL(i2c_adapter_type); EXPORT_SYMBOL_GPL(i2c_adapter_type);
...@@ -1419,8 +1291,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, ...@@ -1419,8 +1291,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
if (of_get_property(node, "wakeup-source", NULL)) if (of_get_property(node, "wakeup-source", NULL))
info.flags |= I2C_CLIENT_WAKE; info.flags |= I2C_CLIENT_WAKE;
request_module("%s%s", I2C_MODULE_PREFIX, info.type);
result = i2c_new_device(adap, &info); result = i2c_new_device(adap, &info);
if (result == NULL) { if (result == NULL) {
dev_err(&adap->dev, "of_i2c: Failure registering %s\n", dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
...@@ -1796,11 +1666,15 @@ void i2c_del_adapter(struct i2c_adapter *adap) ...@@ -1796,11 +1666,15 @@ void i2c_del_adapter(struct i2c_adapter *adap)
/* device name is gone after device_unregister */ /* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
/* clean up the sysfs representation */ /* wait until all references to the device are gone
*
* FIXME: This is old code and should ideally be replaced by an
* alternative which results in decoupling the lifetime of the struct
* device from the i2c_adapter, like spi or netdev do. Any solution
* should be throughly tested with DEBUG_KOBJECT_RELEASE enabled!
*/
init_completion(&adap->dev_released); init_completion(&adap->dev_released);
device_unregister(&adap->dev); device_unregister(&adap->dev);
/* wait for sysfs to drop all references */
wait_for_completion(&adap->dev_released); wait_for_completion(&adap->dev_released);
/* free bus id */ /* free bus id */
...@@ -1859,14 +1733,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) ...@@ -1859,14 +1733,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
if (res) if (res)
return res; return res;
/* Drivers should switch to dev_pm_ops instead. */
if (driver->suspend)
pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
driver->driver.name);
if (driver->resume)
pr_warn("i2c-core: driver [%s] using legacy resume method\n",
driver->driver.name);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients); INIT_LIST_HEAD(&driver->clients);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/i2c-mux.h> #include <linux/i2c-mux.h>
#include <linux/i2c/pca954x.h> #include <linux/i2c/pca954x.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -186,6 +187,8 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -186,6 +187,8 @@ static int pca954x_probe(struct i2c_client *client,
{ {
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *of_node = client->dev.of_node;
bool idle_disconnect_dt;
struct gpio_desc *gpio; struct gpio_desc *gpio;
int num, force, class; int num, force, class;
struct pca954x *data; struct pca954x *data;
...@@ -217,8 +220,13 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -217,8 +220,13 @@ static int pca954x_probe(struct i2c_client *client,
data->type = id->driver_data; data->type = id->driver_data;
data->last_chan = 0; /* force the first selection */ data->last_chan = 0; /* force the first selection */
idle_disconnect_dt = of_node &&
of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
/* Now create an adapter for each channel */ /* Now create an adapter for each channel */
for (num = 0; num < chips[data->type].nchans; num++) { for (num = 0; num < chips[data->type].nchans; num++) {
bool idle_disconnect_pd = false;
force = 0; /* dynamic adap number */ force = 0; /* dynamic adap number */
class = 0; /* no class by default */ class = 0; /* no class by default */
if (pdata) { if (pdata) {
...@@ -229,12 +237,13 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -229,12 +237,13 @@ static int pca954x_probe(struct i2c_client *client,
} else } else
/* discard unconfigured channels */ /* discard unconfigured channels */
break; break;
idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
} }
data->virt_adaps[num] = data->virt_adaps[num] =
i2c_add_mux_adapter(adap, &client->dev, client, i2c_add_mux_adapter(adap, &client->dev, client,
force, num, class, pca954x_select_chan, force, num, class, pca954x_select_chan,
(pdata && pdata->modes[num].deselect_on_exit) (idle_disconnect_pd || idle_disconnect_dt)
? pca954x_deselect_mux : NULL); ? pca954x_deselect_mux : NULL);
if (data->virt_adaps[num] == NULL) { if (data->virt_adaps[num] == NULL) {
......
...@@ -130,8 +130,6 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, ...@@ -130,8 +130,6 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
* @probe: Callback for device binding * @probe: Callback for device binding
* @remove: Callback for device unbinding * @remove: Callback for device unbinding
* @shutdown: Callback for device shutdown * @shutdown: Callback for device shutdown
* @suspend: Callback for device suspend
* @resume: Callback for device resume
* @alert: Alert callback, for example for the SMBus alert protocol * @alert: Alert callback, for example for the SMBus alert protocol
* @command: Callback for bus-wide signaling (optional) * @command: Callback for bus-wide signaling (optional)
* @driver: Device driver model driver * @driver: Device driver model driver
...@@ -174,8 +172,6 @@ struct i2c_driver { ...@@ -174,8 +172,6 @@ struct i2c_driver {
/* driver model interfaces that don't relate to enumeration */ /* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *); void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol. /* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol. * The format and meaning of the data value depends on the protocol.
......
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