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

Pull i2c updates from Wolfram Sang:

 - New drivers: UniPhier (with and without FIFO)

 - some drivers got some bigger rework: ismt, designware, img-scb (rcar
   had to be reverted because issues were showing up just lately)

 - ACPI: reworked the device scanning and added support for muxes

... and quite a lot of driver bugfixes and cleanups this time.  All
files touched outside of the i2c realm have proper acks.

* 'i2c/for-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (70 commits)
  i2c: rcar: Revert the latest refactoring series
  i2c: pnx: remove superfluous assignment
  MAINTAINERS: i2c: drop i2c-pnx maintainer
  MAINTAINERS: i2c: mark also subdirectories as maintained
  i2c: cadence: enable driver for ARM64
  i2c: i801: Document Intel DNV and Broxton
  i2c: at91: manage unexpected RXRDY flag when starting a transfer
  i2c: pnx: Use setup_timer instead of open coding it
  i2c: add ACPI support for I2C mux ports
  acpi: add acpi_preset_companion() stub
  i2c: pxa: Add support for pxa910/988 & new configuration features
  i2c: au1550: Convert to devm_kzalloc and devm_ioremap_resource
  i2c-dev: Fix I2C_SLAVE ioctl comment
  i2c-dev: Fix typo in ioctl name reference
  i2c: sirf: tune the divider to make i2c bus freq more accurate
  i2c: imx: Use -ENXIO as error in the NACK case
  i2c: i801: Add support for Intel Broxton
  i2c: i801: Add support for Intel DNV
  i2c: mediatek: add i2c resume support
  i2c: imx: implement bus recovery
  ...
This commit is contained in:
Linus Torvalds 2015-11-10 11:58:25 -08:00
commit d55fc37856
44 changed files with 1686 additions and 382 deletions

View File

@ -0,0 +1,58 @@
ACPI I2C Muxes
--------------
Describing an I2C device hierarchy that includes I2C muxes requires an ACPI
Device () scope per mux channel.
Consider this topology:
+------+ +------+
| SMB1 |-->| MUX0 |--CH00--> i2c client A (0x50)
| | | 0x70 |--CH01--> i2c client B (0x50)
+------+ +------+
which corresponds to the following ASL:
Device (SMB1)
{
Name (_HID, ...)
Device (MUX0)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate () {
I2cSerialBus (0x70, ControllerInitiated, I2C_SPEED,
AddressingMode7Bit, "^SMB1", 0x00,
ResourceConsumer,,)
}
Device (CH00)
{
Name (_ADR, 0)
Device (CLIA)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate () {
I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
AddressingMode7Bit, "^CH00", 0x00,
ResourceConsumer,,)
}
}
}
Device (CH01)
{
Name (_ADR, 1)
Device (CLIB)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate () {
I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
AddressingMode7Bit, "^CH01", 0x00,
ResourceConsumer,,)
}
}
}
}
}

View File

@ -1,10 +1,10 @@
* Texas Instruments Davinci I2C
* Texas Instruments Davinci/Keystone I2C
This file provides information, what the device node for the
davinci i2c interface contain.
davinci/keystone i2c interface contains.
Required properties:
- compatible: "ti,davinci-i2c";
- compatible: "ti,davinci-i2c" or "ti,keystone-i2c";
- reg : Offset and length of the register set for the device
Recommended properties :

View File

@ -14,6 +14,10 @@ Optional properties:
The absence of the propoerty indicates the default frequency 100 kHz.
- dmas: A list of two dma specifiers, one for each entry in dma-names.
- dma-names: should contain "tx" and "rx".
- scl-gpios: specify the gpio related to SCL pin
- sda-gpios: specify the gpio related to SDA pin
- pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2c
bus recovery, call it "gpio" state
Examples:
@ -37,4 +41,9 @@ i2c0: i2c@40066000 { /* i2c0 on vf610 */
dmas = <&edma0 0 50>,
<&edma0 0 51>;
dma-names = "rx","tx";
pinctrl-names = "default", "gpio";
pinctrl-0 = <&pinctrl_i2c1>;
pinctrl-1 = <&pinctrl_i2c1_gpio>;
scl-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>;
sda-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
};

View File

@ -10,6 +10,7 @@ Required properties:
"renesas,i2c-r8a7792"
"renesas,i2c-r8a7793"
"renesas,i2c-r8a7794"
"renesas,i2c-r8a7795"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt specifier.

View File

@ -10,6 +10,7 @@ Required properties:
- "renesas,iic-r8a7792" (R-Car V2H)
- "renesas,iic-r8a7793" (R-Car M2-N)
- "renesas,iic-r8a7794" (R-Car E2)
- "renesas,iic-r8a7795" (R-Car H3)
- "renesas,iic-sh73a0" (SH-Mobile AG5)
- reg : address start and address range size of device
- interrupts : interrupt of device

View File

@ -0,0 +1,25 @@
UniPhier I2C controller (FIFO-builtin)
Required properties:
- compatible: should be "socionext,uniphier-fi2c".
- #address-cells: should be 1.
- #size-cells: should be 0.
- reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier.
- clocks: phandle to the input clock.
Optional properties:
- clock-frequency: desired I2C bus frequency in Hz. The maximum supported
value is 400000. Defaults to 100000 if not specified.
Examples:
i2c0: i2c@58780000 {
compatible = "socionext,uniphier-fi2c";
reg = <0x58780000 0x80>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 41 4>;
clocks = <&i2c_clk>;
clock-frequency = <100000>;
};

View File

@ -0,0 +1,25 @@
UniPhier I2C controller (FIFO-less)
Required properties:
- compatible: should be "socionext,uniphier-i2c".
- #address-cells: should be 1.
- #size-cells: should be 0.
- reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier.
- clocks: phandle to the input clock.
Optional properties:
- clock-frequency: desired I2C bus frequency in Hz. The maximum supported
value is 400000. Defaults to 100000 if not specified.
Examples:
i2c0: i2c@58400000 {
compatible = "socionext,uniphier-i2c";
reg = <0x58400000 0x40>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 41 1>;
clocks = <&i2c_clk>;
clock-frequency = <100000>;
};

View File

@ -30,6 +30,8 @@ Supported adapters:
* Intel BayTrail (SOC)
* Intel Sunrise Point-H (PCH)
* Intel Sunrise Point-LP (PCH)
* Intel DNV (SOC)
* Intel Broxton (SOC)
Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller

View File

@ -1626,6 +1626,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/boot/dts/uniphier*
F: arch/arm/mach-uniphier/
F: drivers/i2c/busses/i2c-uniphier*
F: drivers/pinctrl/uniphier/
F: drivers/tty/serial/8250/8250_uniphier.c
N: uniphier
@ -5163,6 +5164,7 @@ S: Maintained
F: Documentation/devicetree/bindings/i2c/
F: Documentation/i2c/
F: drivers/i2c/
F: drivers/i2c/*/
F: include/linux/i2c.h
F: include/linux/i2c-*.h
F: include/uapi/linux/i2c.h
@ -8418,12 +8420,6 @@ M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
S: Maintained
F: drivers/pnp/
PNXxxxx I2C DRIVER
M: Vitaly Wool <vitalywool@gmail.com>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-pnx.c
PPP PROTOCOL DRIVERS AND COMPRESSORS
M: Paul Mackerras <paulus@samba.org>
L: linux-ppp@vger.kernel.org

View File

@ -124,6 +124,8 @@ config I2C_I801
BayTrail (SOC)
Sunrise Point-H (PCH)
Sunrise Point-LP (PCH)
DNV (SOC)
Broxton (SOC)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@ -422,7 +424,7 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
config I2C_CADENCE
tristate "Cadence I2C Controller"
depends on ARCH_ZYNQ
depends on ARCH_ZYNQ || ARM64
help
Say yes here to select Cadence I2C Host Controller. This controller is
e.g. used by Xilinx Zynq.
@ -582,10 +584,10 @@ config I2C_IMG
config I2C_IMX
tristate "IMX I2C interface"
depends on ARCH_MXC
depends on ARCH_MXC || ARCH_LAYERSCAPE
help
Say Y here if you want to use the IIC bus controller on
the Freescale i.MX/MXC processors.
the Freescale i.MX/MXC or Layerscape processors.
This driver can also be built as a module. If so, the module
will be called i2c-imx.
@ -902,6 +904,22 @@ config I2C_TEGRA
If you say yes to this option, support will be included for the
I2C controller embedded in NVIDIA Tegra SOCs
config I2C_UNIPHIER
tristate "UniPhier FIFO-less I2C controller"
depends on ARCH_UNIPHIER
help
If you say yes to this option, support will be included for
the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8,
or older UniPhier SoCs.
config I2C_UNIPHIER_F
tristate "UniPhier FIFO-builtin I2C controller"
depends on ARCH_UNIPHIER
help
If you say yes to this option, support will be included for
the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4,
PH1-Pro5, or newer UniPhier SoCs.
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS

View File

@ -87,6 +87,8 @@ obj-$(CONFIG_I2C_ST) += i2c-st.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o

View File

@ -347,8 +347,14 @@ error:
static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
{
if (!dev->buf_len)
/*
* If we are in this case, it means there is garbage data in RHR, so
* delete them.
*/
if (!dev->buf_len) {
at91_twi_read(dev, AT91_TWI_RHR);
return;
}
/* 8bit read works with and without FIFO */
*dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR);
@ -465,19 +471,73 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
if (!irqstatus)
return IRQ_NONE;
else if (irqstatus & AT91_TWI_RXRDY)
/*
* In reception, the behavior of the twi device (before sama5d2) is
* weird. There is some magic about RXRDY flag! When a data has been
* almost received, the reception of a new one is anticipated if there
* is no stop command to send. That is the reason why ask for sending
* the stop command not on the last data but on the second last one.
*
* Unfortunately, we could still have the RXRDY flag set even if the
* transfer is done and we have read the last data. It might happen
* when the i2c slave device sends too quickly data after receiving the
* ack from the master. The data has been almost received before having
* the order to send stop. In this case, sending the stop command could
* cause a RXRDY interrupt with a TXCOMP one. It is better to manage
* the RXRDY interrupt first in order to not keep garbage data in the
* Receive Holding Register for the next transfer.
*/
if (irqstatus & AT91_TWI_RXRDY)
at91_twi_read_next_byte(dev);
else if (irqstatus & AT91_TWI_TXRDY)
at91_twi_write_next_byte(dev);
/* catch error flags */
dev->transfer_status |= status;
/*
* When a NACK condition is detected, the I2C controller sets the NACK,
* TXCOMP and TXRDY bits all together in the Status Register (SR).
*
* 1 - Handling NACK errors with CPU write transfer.
*
* In such case, we should not write the next byte into the Transmit
* Holding Register (THR) otherwise the I2C controller would start a new
* transfer and the I2C slave is likely to reply by another NACK.
*
* 2 - Handling NACK errors with DMA write transfer.
*
* By setting the TXRDY bit in the SR, the I2C controller also triggers
* the DMA controller to write the next data into the THR. Then the
* result depends on the hardware version of the I2C controller.
*
* 2a - Without support of the Alternative Command mode.
*
* This is the worst case: the DMA controller is triggered to write the
* next data into the THR, hence starting a new transfer: the I2C slave
* is likely to reply by another NACK.
* Concurrently, this interrupt handler is likely to be called to manage
* the first NACK before the I2C controller detects the second NACK and
* sets once again the NACK bit into the SR.
* When handling the first NACK, this interrupt handler disables the I2C
* controller interruptions, especially the NACK interrupt.
* Hence, the NACK bit is pending into the SR. This is why we should
* read the SR to clear all pending interrupts at the beginning of
* at91_do_twi_transfer() before actually starting a new transfer.
*
* 2b - With support of the Alternative Command mode.
*
* When a NACK condition is detected, the I2C controller also locks the
* THR (and sets the LOCK bit in the SR): even though the DMA controller
* is triggered by the TXRDY bit to write the next data into the THR,
* this data actually won't go on the I2C bus hence a second NACK is not
* generated.
*/
if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) {
at91_disable_twi_interrupts(dev);
complete(&dev->cmd_complete);
} else if (irqstatus & AT91_TWI_TXRDY) {
at91_twi_write_next_byte(dev);
}
/* catch error flags */
dev->transfer_status |= status;
return IRQ_HANDLED;
}
@ -537,6 +597,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
reinit_completion(&dev->cmd_complete);
dev->transfer_status = 0;
/* Clear pending interrupts, such as NACK. */
at91_twi_read(dev, AT91_TWI_SR);
if (dev->fifo_size) {
unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR);
@ -558,11 +621,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
} else if (dev->msg->flags & I2C_M_RD) {
unsigned start_flags = AT91_TWI_START;
if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
dev_err(dev->dev, "RXRDY still set!");
at91_twi_read(dev, AT91_TWI_RHR);
}
/* if only one byte is to be read, immediately stop transfer */
if (!has_alt_cmd && dev->buf_len <= 1 &&
!(dev->msg->flags & I2C_M_RECV_LEN))

View File

@ -48,7 +48,6 @@ struct i2c_au1550_data {
void __iomem *psc_base;
int xfer_timeout;
struct i2c_adapter adap;
struct resource *ioarea;
};
static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v)
@ -284,10 +283,10 @@ static void i2c_au1550_setup(struct i2c_au1550_data *priv)
/* Set the protocol timer values. See Table 71 in the
* Au1550 Data Book for standard timing values.
*/
WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
PSC_SMBTMR_SET_CH(15));
WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(20) | \
PSC_SMBTMR_SET_PU(20) | PSC_SMBTMR_SET_SH(20) | \
PSC_SMBTMR_SET_SU(20) | PSC_SMBTMR_SET_CL(20) | \
PSC_SMBTMR_SET_CH(20));
cfg |= PSC_SMBCFG_DE_ENABLE;
WR(priv, PSC_SMBCFG, cfg);
@ -315,30 +314,16 @@ i2c_au1550_probe(struct platform_device *pdev)
struct resource *r;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
ret = -ENODEV;
goto out;
}
priv->psc_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(priv->psc_base))
return PTR_ERR(priv->psc_base);
priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto out;
}
priv->ioarea = request_mem_region(r->start, resource_size(r),
pdev->name);
if (!priv->ioarea) {
ret = -EBUSY;
goto out_mem;
}
priv->psc_base = ioremap(r->start, resource_size(r));
if (!priv->psc_base) {
ret = -EIO;
goto out_map;
}
priv->xfer_timeout = 200;
priv->adap.nr = pdev->id;
@ -351,20 +336,13 @@ i2c_au1550_probe(struct platform_device *pdev)
i2c_au1550_setup(priv);
ret = i2c_add_numbered_adapter(&priv->adap);
if (ret == 0) {
platform_set_drvdata(pdev, priv);
return 0;
if (ret) {
i2c_au1550_disable(priv);
return ret;
}
i2c_au1550_disable(priv);
iounmap(priv->psc_base);
out_map:
release_resource(priv->ioarea);
kfree(priv->ioarea);
out_mem:
kfree(priv);
out:
return ret;
platform_set_drvdata(pdev, priv);
return 0;
}
static int i2c_au1550_remove(struct platform_device *pdev)
@ -373,10 +351,6 @@ static int i2c_au1550_remove(struct platform_device *pdev)
i2c_del_adapter(&priv->adap);
i2c_au1550_disable(priv);
iounmap(priv->psc_base);
release_resource(priv->ioarea);
kfree(priv->ioarea);
kfree(priv);
return 0;
}

View File

@ -181,6 +181,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
u32 clkh;
u32 clkl;
u32 input_clock = clk_get_rate(dev->clk);
struct device_node *of_node = dev->dev->of_node;
/* NOTE: I2C Clock divider programming info
* As per I2C specs the following formulas provide prescaler
@ -196,6 +197,9 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
* where if PSC == 0, d = 7,
* if PSC == 1, d = 6
* if PSC > 1 , d = 5
*
* Note:
* d is always 6 on Keystone I2C controller
*/
/* get minimum of 7 MHz clock, but max of 12 MHz */
@ -204,6 +208,9 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
psc++; /* better to run under spec than over */
d = (psc >= 2) ? 5 : 7 - psc;
if (of_node && of_device_is_compatible(of_node, "ti,keystone-i2c"))
d = 6;
clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000));
/* Avoid driving the bus too fast because of rounding errors above */
if (input_clock / (psc + 1) / clk > pdata->bus_freq * 1000)
@ -726,6 +733,7 @@ static struct i2c_algorithm i2c_davinci_algo = {
static const struct of_device_id davinci_i2c_of_match[] = {
{.compatible = "ti,davinci-i2c", },
{.compatible = "ti,keystone-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, davinci_i2c_of_match);

View File

@ -165,7 +165,7 @@ static char *abort_sources[] = {
"lost arbitration",
};
u32 dw_readl(struct dw_i2c_dev *dev, int offset)
static u32 dw_readl(struct dw_i2c_dev *dev, int offset)
{
u32 value;
@ -181,7 +181,7 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
return value;
}
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
static void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
{
if (dev->accessor_flags & ACCESS_SWAP)
b = swab32(b);
@ -438,7 +438,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
__i2c_dw_enable(dev, true);
/* Clear and enable interrupts */
i2c_dw_clear_int(dev);
dw_readl(dev, DW_IC_CLR_INTR);
dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
}
@ -618,7 +618,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
/*
* Prepare controller for a transaction and call i2c_dw_xfer_msg
*/
int
static int
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
@ -702,14 +702,17 @@ done_nolock:
return ret;
}
EXPORT_SYMBOL_GPL(i2c_dw_xfer);
u32 i2c_dw_func(struct i2c_adapter *adap)
static u32 i2c_dw_func(struct i2c_adapter *adap)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
return dev->functionality;
}
EXPORT_SYMBOL_GPL(i2c_dw_func);
static struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{
@ -770,7 +773,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
* Interrupt service routine. This gets called whenever an I2C interrupt
* occurs.
*/
irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
u32 stat, enabled;
@ -813,20 +816,6 @@ tx_aborted:
return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(i2c_dw_isr);
void i2c_dw_enable(struct dw_i2c_dev *dev)
{
/* Enable the adapter */
__i2c_dw_enable(dev, true);
}
EXPORT_SYMBOL_GPL(i2c_dw_enable);
u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
{
return dw_readl(dev, DW_IC_ENABLE);
}
EXPORT_SYMBOL_GPL(i2c_dw_is_enabled);
void i2c_dw_disable(struct dw_i2c_dev *dev)
{
@ -839,12 +828,6 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
}
EXPORT_SYMBOL_GPL(i2c_dw_disable);
void i2c_dw_clear_int(struct dw_i2c_dev *dev)
{
dw_readl(dev, DW_IC_CLR_INTR);
}
EXPORT_SYMBOL_GPL(i2c_dw_clear_int);
void i2c_dw_disable_int(struct dw_i2c_dev *dev)
{
dw_writel(dev, 0, DW_IC_INTR_MASK);
@ -857,5 +840,40 @@ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
}
EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
int r;
init_completion(&dev->cmd_complete);
mutex_init(&dev->lock);
r = i2c_dw_init(dev);
if (r)
return r;
snprintf(adap->name, sizeof(adap->name),
"Synopsys DesignWare I2C adapter");
adap->algo = &i2c_dw_algo;
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
i2c_dw_disable_int(dev);
r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
dev_name(dev->dev), dev);
if (r) {
dev_err(dev->dev, "failure requesting irq %i: %d\n",
dev->irq, r);
return r;
}
r = i2c_add_numbered_adapter(adap);
if (r)
dev_err(dev->dev, "failure adding adapter: %d\n", r);
return r;
}
EXPORT_SYMBOL_GPL(i2c_dw_probe);
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
MODULE_LICENSE("GPL");

View File

@ -112,19 +112,11 @@ struct dw_i2c_dev {
#define ACCESS_SWAP 0x00000001
#define ACCESS_16BIT 0x00000002
extern u32 dw_readl(struct dw_i2c_dev *dev, int offset);
extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
extern int i2c_dw_init(struct dw_i2c_dev *dev);
extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
int num);
extern u32 i2c_dw_func(struct i2c_adapter *adap);
extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id);
extern void i2c_dw_enable(struct dw_i2c_dev *dev);
extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev);
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_disable_int(struct dw_i2c_dev *dev);
extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
extern int i2c_dw_probe(struct dw_i2c_dev *dev);
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);

View File

@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/acpi.h>
#include "i2c-designware-core.h"
#define DRIVER_NAME "i2c-designware-pci"
@ -158,11 +159,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
},
};
static struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
#ifdef CONFIG_PM
static int i2c_dw_pci_suspend(struct device *dev)
{
@ -222,13 +218,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
if (!dev)
return -ENOMEM;
init_completion(&dev->cmd_complete);
mutex_init(&dev->lock);
dev->clk = NULL;
dev->controller = controller;
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev;
dev->irq = pdev->irq;
dev->functionality = controller->functionality |
DW_DEFAULT_FUNCTIONALITY;
@ -246,34 +241,16 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->tx_fifo_depth = controller->tx_fifo_depth;
dev->rx_fifo_depth = controller->rx_fifo_depth;
r = i2c_dw_init(dev);
if (r)
return r;
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = 0;
adap->algo = &i2c_dw_algo;
adap->dev.parent = &pdev->dev;
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->nr = controller->bus_num;
snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr,
IRQF_SHARED | IRQF_COND_SUSPEND, adap->name, dev);
if (r) {
dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
r = i2c_dw_probe(dev);
if (r)
return r;
}
i2c_dw_disable_int(dev);
i2c_dw_clear_int(dev);
r = i2c_add_numbered_adapter(adap);
if (r) {
dev_err(&pdev->dev, "failure adding adapter\n");
return r;
}
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);

View File

@ -42,10 +42,6 @@
#include <linux/platform_data/i2c-designware.h>
#include "i2c-designware-core.h"
static struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
return clk_get_rate(dev->clk)/1000;
@ -97,7 +93,6 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
static int dw_i2c_acpi_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
const struct acpi_device_id *id;
dev->adapter.nr = -1;
dev->tx_fifo_depth = 32;
@ -111,29 +106,9 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);
/*
* Provide a way for Designware I2C host controllers that are not
* based on Intel LPSS to specify their input clock frequency via
* id->driver_data.
*/
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
clk_register_fixed_rate(&pdev->dev, dev_name(&pdev->dev), NULL,
CLK_IS_ROOT, id->driver_data);
return 0;
}
static void dw_i2c_acpi_unconfigure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
const struct acpi_device_id *id;
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
clk_unregister(dev->clk);
}
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "INT33C3", 0 },
@ -141,7 +116,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT3433", 0 },
{ "80860F41", 0 },
{ "808622C1", 0 },
{ "AMD0010", 133 * 1000 * 1000 },
{ "AMD0010", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
@ -150,10 +125,9 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
{
return -ENODEV;
}
static inline void dw_i2c_acpi_unconfigure(struct platform_device *pdev) { }
#endif
static int dw_i2c_probe(struct platform_device *pdev)
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
@ -175,8 +149,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
init_completion(&dev->cmd_complete);
mutex_init(&dev->lock);
dev->dev = &pdev->dev;
dev->irq = irq;
platform_set_drvdata(pdev, dev);
@ -251,26 +223,11 @@ static int dw_i2c_probe(struct platform_device *pdev)
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
dev->adapter.nr = pdev->id;
}
r = i2c_dw_init(dev);
if (r)
return r;
i2c_dw_disable_int(dev);
r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
pdev->name, dev);
if (r) {
dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
return r;
}
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
sizeof(adap->name));
adap->algo = &i2c_dw_algo;
adap->dev.parent = &pdev->dev;
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->dev.of_node = pdev->dev.of_node;
if (dev->pm_runtime_disabled) {
@ -282,9 +239,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
}
r = i2c_add_numbered_adapter(adap);
r = i2c_dw_probe(dev);
if (r) {
dev_err(&pdev->dev, "failure adding adapter\n");
pm_runtime_disable(&pdev->dev);
return r;
}
@ -292,7 +248,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
return 0;
}
static int dw_i2c_remove(struct platform_device *pdev)
static int dw_i2c_plat_remove(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
@ -306,9 +262,6 @@ static int dw_i2c_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_unconfigure(pdev);
return 0;
}
@ -321,23 +274,23 @@ MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif
#ifdef CONFIG_PM_SLEEP
static int dw_i2c_prepare(struct device *dev)
static int dw_i2c_plat_prepare(struct device *dev)
{
return pm_runtime_suspended(dev);
}
static void dw_i2c_complete(struct device *dev)
static void dw_i2c_plat_complete(struct device *dev)
{
if (dev->power.direct_complete)
pm_request_resume(dev);
}
#else
#define dw_i2c_prepare NULL
#define dw_i2c_complete NULL
#define dw_i2c_plat_prepare NULL
#define dw_i2c_plat_complete NULL
#endif
#ifdef CONFIG_PM
static int dw_i2c_suspend(struct device *dev)
static int dw_i2c_plat_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@ -348,7 +301,7 @@ static int dw_i2c_suspend(struct device *dev)
return 0;
}
static int dw_i2c_resume(struct device *dev)
static int dw_i2c_plat_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@ -362,10 +315,10 @@ static int dw_i2c_resume(struct device *dev)
}
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
.prepare = dw_i2c_prepare,
.complete = dw_i2c_complete,
SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_suspend, dw_i2c_resume)
SET_RUNTIME_PM_OPS(dw_i2c_suspend, dw_i2c_resume, NULL)
.prepare = dw_i2c_plat_prepare,
.complete = dw_i2c_plat_complete,
SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
};
#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
@ -377,8 +330,8 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
MODULE_ALIAS("platform:i2c_designware");
static struct platform_driver dw_i2c_driver = {
.probe = dw_i2c_probe,
.remove = dw_i2c_remove,
.probe = dw_i2c_plat_probe,
.remove = dw_i2c_plat_remove,
.driver = {
.name = "i2c_designware",
.of_match_table = of_match_ptr(dw_i2c_of_match),

View File

@ -60,6 +60,8 @@
* BayTrail (SOC) 0x0f12 32 hard yes yes yes
* Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
* Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes
* DNV (SOC) 0x19df 32 hard yes yes yes
* Broxton (SOC) 0x5ad4 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@ -202,6 +204,8 @@
#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_DNV_SMBUS 0x19df
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
struct i801_mux_config {
char *gpio_chip;
@ -863,6 +867,8 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
{ 0, }
};
@ -1251,11 +1257,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->adapter.owner = THIS_MODULE;
priv->adapter.class = i801_get_adapter_class(priv);
priv->adapter.algo = &smbus_algorithm;
priv->adapter.dev.parent = &dev->dev;
ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
priv->adapter.retries = 3;
priv->pci_dev = dev;
switch (dev->device) {
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
priv->features |= FEATURE_SMBUS_PEC;
@ -1381,12 +1391,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
i801_add_tco(priv);
/* set up the sysfs linkage to our parent device */
priv->adapter.dev.parent = &dev->dev;
/* Retry up to 3 times on lost arbitration */
priv->adapter.retries = 3;
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
"SMBus I801 adapter at %04lx", priv->smba);
err = i2c_add_adapter(&priv->adapter);

View File

@ -798,6 +798,7 @@ static const struct of_device_id ibm_iic_match[] = {
{ .compatible = "ibm,iic", },
{}
};
MODULE_DEVICE_TABLE(of, ibm_iic_match);
static struct platform_driver ibm_iic_driver = {
.driver = {

View File

@ -278,8 +278,6 @@
#define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err)))
#define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M)
#define REL_SOC_IP_SCB_2_2_1 0x00020201
enum img_i2c_mode {
MODE_INACTIVE,
MODE_RAW,
@ -536,6 +534,7 @@ static void img_i2c_read_fifo(struct img_i2c *i2c)
u32 fifo_status;
u8 data;
img_i2c_wr_rd_fence(i2c);
fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
if (fifo_status & FIFO_READ_EMPTY)
break;
@ -544,7 +543,6 @@ static void img_i2c_read_fifo(struct img_i2c *i2c)
*i2c->msg.buf = data;
img_i2c_writel(i2c, SCB_READ_FIFO_REG, 0xff);
img_i2c_wr_rd_fence(i2c);
i2c->msg.len--;
i2c->msg.buf++;
}
@ -556,12 +554,12 @@ static void img_i2c_write_fifo(struct img_i2c *i2c)
while (i2c->msg.len) {
u32 fifo_status;
img_i2c_wr_rd_fence(i2c);
fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
if (fifo_status & FIFO_WRITE_FULL)
break;
img_i2c_writel(i2c, SCB_WRITE_DATA_REG, *i2c->msg.buf);
img_i2c_wr_rd_fence(i2c);
i2c->msg.len--;
i2c->msg.buf++;
}
@ -859,7 +857,7 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c,
}
/* Enable transaction halt on start bit */
if (!i2c->last_msg && i2c->line_status & LINESTAT_START_BIT_DET) {
if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) {
img_i2c_transaction_halt(i2c, true);
/* we're no longer interested in the slave event */
i2c->int_enable &= ~INT_SLAVE_EVENT;
@ -1062,6 +1060,15 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
i2c->last_msg = (i == num - 1);
reinit_completion(&i2c->msg_complete);
/*
* Clear line status and all interrupts before starting a
* transfer, as we may have unserviced interrupts from
* previous transfers that might be handled in the context
* of the new transfer.
*/
img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0);
img_i2c_writel(i2c, SCB_CLEAR_REG, ~0);
if (atomic)
img_i2c_atomic_start(i2c);
else if (msg->flags & I2C_M_RD)
@ -1120,13 +1127,8 @@ static int img_i2c_init(struct img_i2c *i2c)
return -EINVAL;
}
if (rev == REL_SOC_IP_SCB_2_2_1) {
i2c->need_wr_rd_fence = true;
dev_info(i2c->adap.dev.parent, "fence quirk enabled");
}
bitrate_khz = i2c->bitrate / 1000;
clk_khz = clk_get_rate(i2c->scb_clk) / 1000;
/* Fencing enabled by default. */
i2c->need_wr_rd_fence = true;
/* Determine what mode we're in from the bitrate */
timing = timings[0];
@ -1136,6 +1138,17 @@ static int img_i2c_init(struct img_i2c *i2c)
break;
}
}
if (i2c->bitrate > timings[ARRAY_SIZE(timings) - 1].max_bitrate) {
dev_warn(i2c->adap.dev.parent,
"requested bitrate (%u) is higher than the max bitrate supported (%u)\n",
i2c->bitrate,
timings[ARRAY_SIZE(timings) - 1].max_bitrate);
timing = timings[ARRAY_SIZE(timings) - 1];
i2c->bitrate = timing.max_bitrate;
}
bitrate_khz = i2c->bitrate / 1000;
clk_khz = clk_get_rate(i2c->scb_clk) / 1000;
/* Find the prescale that would give us that inc (approx delay = 0) */
prescale = SCB_OPT_INC * clk_khz / (256 * 16 * bitrate_khz);
@ -1182,32 +1195,32 @@ static int img_i2c_init(struct img_i2c *i2c)
((bitrate_khz * clk_period) / 2))
int_bitrate++;
/* Setup TCKH value */
tckh = timing.tckh / clk_period;
if (timing.tckh % clk_period)
tckh++;
if (tckh > 0)
data = tckh - 1;
else
data = 0;
img_i2c_writel(i2c, SCB_TIME_TCKH_REG, data);
/* Setup TCKL value */
/*
* Setup clock duty cycle, start with 50% and adjust TCKH and TCKL
* values from there if they don't meet minimum timing requirements
*/
tckh = int_bitrate / 2;
tckl = int_bitrate - tckh;
if (tckl > 0)
data = tckl - 1;
else
data = 0;
/* Adjust TCKH and TCKL values */
data = DIV_ROUND_UP(timing.tckl, clk_period);
img_i2c_writel(i2c, SCB_TIME_TCKL_REG, data);
if (tckl < data) {
tckl = data;
tckh = int_bitrate - tckl;
}
if (tckh > 0)
--tckh;
if (tckl > 0)
--tckl;
img_i2c_writel(i2c, SCB_TIME_TCKH_REG, tckh);
img_i2c_writel(i2c, SCB_TIME_TCKL_REG, tckl);
/* Setup TSDH value */
tsdh = timing.tsdh / clk_period;
if (timing.tsdh % clk_period)
tsdh++;
tsdh = DIV_ROUND_UP(timing.tsdh, clk_period);
if (tsdh > 1)
data = tsdh - 1;

View File

@ -49,6 +49,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/of_gpio.h>
#include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
@ -207,6 +208,11 @@ struct imx_i2c_struct {
unsigned int cur_clk;
unsigned int bitrate;
const struct imx_i2c_hwdata *hwdata;
struct i2c_bus_recovery_info rinfo;
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_pins_default;
struct pinctrl_state *pinctrl_pins_gpio;
struct imx_i2c_dma *dma;
};
@ -461,7 +467,7 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
{
if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
return -EIO; /* No ACK */
return -ENXIO; /* No ACK */
}
dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__);
@ -896,6 +902,13 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
/* Start I2C transfer */
result = i2c_imx_start(i2c_imx);
if (result) {
if (i2c_imx->adapter.bus_recovery_info) {
i2c_recover_bus(&i2c_imx->adapter);
result = i2c_imx_start(i2c_imx);
}
}
if (result)
goto fail0;
@ -956,6 +969,55 @@ fail0:
return (result < 0) ? result : num;
}
static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
{
struct imx_i2c_struct *i2c_imx;
i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio);
}
static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
{
struct imx_i2c_struct *i2c_imx;
i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
}
static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
struct platform_device *pdev)
{
struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo;
i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
"gpio");
rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
"sda-gpios", 0, NULL);
rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
"scl-gpios", 0, NULL);
if (!gpio_is_valid(rinfo->sda_gpio) ||
!gpio_is_valid(rinfo->scl_gpio) ||
IS_ERR(i2c_imx->pinctrl_pins_default) ||
IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
dev_dbg(&pdev->dev, "recovery information incomplete\n");
return;
}
dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n",
rinfo->sda_gpio, rinfo->scl_gpio);
rinfo->prepare_recovery = i2c_imx_prepare_recovery;
rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
rinfo->recover_bus = i2c_generic_gpio_recovery;
i2c_imx->adapter.bus_recovery_info = rinfo;
}
static u32 i2c_imx_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
@ -1023,6 +1085,13 @@ static int i2c_imx_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "can't enable I2C clock\n");
return ret;
}
i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(i2c_imx->pinctrl)) {
ret = PTR_ERR(i2c_imx->pinctrl);
goto clk_disable;
}
/* Request IRQ */
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
pdev->name, i2c_imx);
@ -1056,6 +1125,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
goto clk_disable;
}
i2c_imx_init_recovery_info(i2c_imx, pdev);
/* Set up platform driver data */
platform_set_drvdata(pdev, i2c_imx);
clk_disable_unprepare(i2c_imx->clk);

View File

@ -165,14 +165,13 @@ struct ismt_desc {
struct ismt_priv {
struct i2c_adapter adapter;
void *smba; /* PCI BAR */
void __iomem *smba; /* PCI BAR */
struct pci_dev *pci_dev;
struct ismt_desc *hw; /* descriptor virt base addr */
dma_addr_t io_rng_dma; /* descriptor HW base addr */
u8 head; /* ring buffer head pointer */
struct completion cmp; /* interrupt completion */
u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */
bool using_msi; /* type of interrupt flag */
};
/**
@ -398,7 +397,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);
/* Initialize common control bits */
if (likely(priv->using_msi))
if (likely(pci_dev_msi_enabled(priv->pci_dev)))
desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR;
else
desc->control = ISMT_DESC_FAIR;
@ -789,11 +788,8 @@ static int ismt_int_init(struct ismt_priv *priv)
/* Try using MSI interrupts */
err = pci_enable_msi(priv->pci_dev);
if (err) {
dev_warn(&priv->pci_dev->dev,
"Unable to use MSI interrupts, falling back to legacy\n");
if (err)
goto intx;
}
err = devm_request_irq(&priv->pci_dev->dev,
priv->pci_dev->irq,
@ -806,11 +802,13 @@ static int ismt_int_init(struct ismt_priv *priv)
goto intx;
}
priv->using_msi = true;
goto done;
return 0;
/* Try using legacy interrupts */
intx:
dev_warn(&priv->pci_dev->dev,
"Unable to use MSI interrupts, falling back to legacy\n");
err = devm_request_irq(&priv->pci_dev->dev,
priv->pci_dev->irq,
ismt_do_interrupt,
@ -819,12 +817,9 @@ intx:
priv);
if (err) {
dev_err(&priv->pci_dev->dev, "no usable interrupts\n");
return -ENODEV;
return err;
}
priv->using_msi = false;
done:
return 0;
}
@ -847,17 +842,13 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
pci_set_drvdata(pdev, priv);
i2c_set_adapdata(&priv->adapter, priv);
priv->adapter.owner = THIS_MODULE;
priv->adapter.class = I2C_CLASS_HWMON;
priv->adapter.algo = &smbus_algorithm;
/* set up the sysfs linkage to our parent device */
priv->adapter.dev.parent = &pdev->dev;
/* number of retries on lost arbitration */
ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
priv->adapter.retries = ISMT_MAX_RETRIES;
priv->pci_dev = pdev;
@ -904,8 +895,7 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
priv->smba = pcim_iomap(pdev, SMBBAR, len);
if (!priv->smba) {
dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n");
err = -ENODEV;
goto fail;
return -ENODEV;
}
if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) ||
@ -915,32 +905,26 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
DMA_BIT_MASK(32)) != 0)) {
dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n",
pdev);
err = -ENODEV;
goto fail;
return -ENODEV;
}
}
err = ismt_dev_init(priv);
if (err)
goto fail;
return err;
ismt_hw_init(priv);
err = ismt_int_init(priv);
if (err)
goto fail;
return err;
err = i2c_add_adapter(&priv->adapter);
if (err) {
dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n");
err = -ENODEV;
goto fail;
return -ENODEV;
}
return 0;
fail:
pci_release_region(pdev, SMBBAR);
return err;
}
/**
@ -952,47 +936,13 @@ static void ismt_remove(struct pci_dev *pdev)
struct ismt_priv *priv = pci_get_drvdata(pdev);
i2c_del_adapter(&priv->adapter);
pci_release_region(pdev, SMBBAR);
}
/**
* ismt_suspend() - place the device in suspend
* @pdev: PCI-Express device
* @mesg: PM message
*/
#ifdef CONFIG_PM
static int ismt_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
return 0;
}
/**
* ismt_resume() - PCI resume code
* @pdev: PCI-Express device
*/
static int ismt_resume(struct pci_dev *pdev)
{
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
return pci_enable_device(pdev);
}
#else
#define ismt_suspend NULL
#define ismt_resume NULL
#endif
static struct pci_driver ismt_driver = {
.name = "ismt_smbus",
.id_table = ismt_ids,
.probe = ismt_probe,
.remove = ismt_remove,
.suspend = ismt_suspend,
.resume = ismt_resume,
};
module_pci_driver(ismt_driver);

View File

@ -475,6 +475,7 @@ static const struct of_device_id meson_i2c_match[] = {
{ .compatible = "amlogic,meson6-i2c" },
{ },
};
MODULE_DEVICE_TABLE(of, meson_i2c_match);
static struct platform_driver meson_i2c_driver = {
.probe = meson_i2c_probe,

View File

@ -728,11 +728,27 @@ static int mtk_i2c_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int mtk_i2c_resume(struct device *dev)
{
struct mtk_i2c *i2c = dev_get_drvdata(dev);
mtk_i2c_init_hw(i2c);
return 0;
}
#endif
static const struct dev_pm_ops mtk_i2c_pm = {
SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume)
};
static struct platform_driver mtk_i2c_driver = {
.probe = mtk_i2c_probe,
.remove = mtk_i2c_remove,
.driver = {
.name = I2C_DRV_NAME,
.pm = &mtk_i2c_pm,
.of_match_table = of_match_ptr(mtk_i2c_of_match),
},
};

View File

@ -92,6 +92,16 @@ static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value)
iowrite32(value, i2c->base + (reg << i2c->reg_shift));
}
static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value)
{
iowrite16be(value, i2c->base + (reg << i2c->reg_shift));
}
static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value)
{
iowrite32be(value, i2c->base + (reg << i2c->reg_shift));
}
static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg)
{
return ioread8(i2c->base + (reg << i2c->reg_shift));
@ -107,6 +117,16 @@ static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg)
return ioread32(i2c->base + (reg << i2c->reg_shift));
}
static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg)
{
return ioread16be(i2c->base + (reg << i2c->reg_shift));
}
static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg)
{
return ioread32be(i2c->base + (reg << i2c->reg_shift));
}
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
{
i2c->setreg(i2c, reg, value);
@ -428,6 +448,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
i2c->reg_io_width = 1; /* Set to default value */
if (!i2c->setreg || !i2c->getreg) {
bool be = pdata ? pdata->big_endian :
of_device_is_big_endian(pdev->dev.of_node);
switch (i2c->reg_io_width) {
case 1:
i2c->setreg = oc_setreg_8;
@ -435,13 +458,13 @@ static int ocores_i2c_probe(struct platform_device *pdev)
break;
case 2:
i2c->setreg = oc_setreg_16;
i2c->getreg = oc_getreg_16;
i2c->setreg = be ? oc_setreg_16be : oc_setreg_16;
i2c->getreg = be ? oc_getreg_16be : oc_getreg_16;
break;
case 4:
i2c->setreg = oc_setreg_32;
i2c->getreg = oc_getreg_32;
i2c->setreg = be ? oc_setreg_32be : oc_setreg_32;
i2c->getreg = be ? oc_getreg_32be : oc_getreg_32;
break;
default:

View File

@ -496,7 +496,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
struct i2c_msg *pmsg;
int rc = 0, completed = 0, i;
struct i2c_pnx_algo_data *alg_data = adap->algo_data;
u32 stat = ioread32(I2C_REG_STS(alg_data));
u32 stat;
dev_dbg(&alg_data->adapter.dev,
"%s(): entering: %d messages, stat = %04x.\n",
@ -659,9 +659,8 @@ static int i2c_pnx_probe(struct platform_device *pdev)
if (IS_ERR(alg_data->clk))
return PTR_ERR(alg_data->clk);
init_timer(&alg_data->mif.timer);
alg_data->mif.timer.function = i2c_pnx_timeout;
alg_data->mif.timer.data = (unsigned long)alg_data;
setup_timer(&alg_data->mif.timer, i2c_pnx_timeout,
(unsigned long)alg_data);
snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
"%s", pdev->name);

View File

@ -46,12 +46,15 @@ struct pxa_reg_layout {
u32 icr;
u32 isr;
u32 isar;
u32 ilcr;
u32 iwcr;
};
enum pxa_i2c_types {
REGS_PXA2XX,
REGS_PXA3XX,
REGS_CE4100,
REGS_PXA910,
};
/*
@ -79,12 +82,22 @@ static struct pxa_reg_layout pxa_reg_layout[] = {
.isr = 0x04,
/* no isar register */
},
[REGS_PXA910] = {
.ibmr = 0x00,
.idbr = 0x08,
.icr = 0x10,
.isr = 0x18,
.isar = 0x20,
.ilcr = 0x28,
.iwcr = 0x30,
},
};
static const struct platform_device_id i2c_pxa_id_table[] = {
{ "pxa2xx-i2c", REGS_PXA2XX },
{ "pxa3xx-pwri2c", REGS_PXA3XX },
{ "ce4100-i2c", REGS_CE4100 },
{ "pxa910-i2c", REGS_PXA910 },
{ },
};
MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
@ -124,6 +137,23 @@ MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
#define ISR_SAD (1 << 9) /* slave address detected */
#define ISR_BED (1 << 10) /* bus error no ACK/NAK */
/* bit field shift & mask */
#define ILCR_SLV_SHIFT 0
#define ILCR_SLV_MASK (0x1FF << ILCR_SLV_SHIFT)
#define ILCR_FLV_SHIFT 9
#define ILCR_FLV_MASK (0x1FF << ILCR_FLV_SHIFT)
#define ILCR_HLVL_SHIFT 18
#define ILCR_HLVL_MASK (0x1FF << ILCR_HLVL_SHIFT)
#define ILCR_HLVH_SHIFT 27
#define ILCR_HLVH_MASK (0x1F << ILCR_HLVH_SHIFT)
#define IWCR_CNT_SHIFT 0
#define IWCR_CNT_MASK (0x1F << IWCR_CNT_SHIFT)
#define IWCR_HS_CNT1_SHIFT 5
#define IWCR_HS_CNT1_MASK (0x1F << IWCR_HS_CNT1_SHIFT)
#define IWCR_HS_CNT2_SHIFT 10
#define IWCR_HS_CNT2_MASK (0x1F << IWCR_HS_CNT2_SHIFT)
struct pxa_i2c {
spinlock_t lock;
wait_queue_head_t wait;
@ -150,6 +180,8 @@ struct pxa_i2c {
void __iomem *reg_icr;
void __iomem *reg_isr;
void __iomem *reg_isar;
void __iomem *reg_ilcr;
void __iomem *reg_iwcr;
unsigned long iobase;
unsigned long iosize;
@ -168,6 +200,8 @@ struct pxa_i2c {
#define _ICR(i2c) ((i2c)->reg_icr)
#define _ISR(i2c) ((i2c)->reg_isr)
#define _ISAR(i2c) ((i2c)->reg_isar)
#define _ILCR(i2c) ((i2c)->reg_ilcr)
#define _IWCR(i2c) ((i2c)->reg_iwcr)
/*
* I2C Slave mode address
@ -1102,7 +1136,7 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
static const struct of_device_id i2c_pxa_dt_ids[] = {
{ .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
{ .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
{ .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX },
{ .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 },
{}
};
MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
@ -1203,6 +1237,11 @@ static int i2c_pxa_probe(struct platform_device *dev)
if (i2c_type != REGS_CE4100)
i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
if (i2c_type == REGS_PXA910) {
i2c->reg_ilcr = i2c->reg_base + pxa_reg_layout[i2c_type].ilcr;
i2c->reg_iwcr = i2c->reg_base + pxa_reg_layout[i2c_type].iwcr;
}
i2c->iobase = res->start;
i2c->iosize = resource_size(res);

View File

@ -27,7 +27,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/i2c/i2c-rcar.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
@ -103,6 +102,7 @@
enum rcar_i2c_type {
I2C_RCAR_GEN1,
I2C_RCAR_GEN2,
I2C_RCAR_GEN3,
};
struct rcar_i2c_priv {
@ -178,6 +178,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
cdf_width = 2;
break;
case I2C_RCAR_GEN2:
case I2C_RCAR_GEN3:
cdf_width = 3;
break;
default:
@ -625,13 +626,13 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
{},
};
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
static int rcar_i2c_probe(struct platform_device *pdev)
{
struct i2c_rcar_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct rcar_i2c_priv *priv;
struct i2c_adapter *adap;
struct resource *res;
@ -650,15 +651,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
}
bus_speed = 100000; /* default 100 kHz */
ret = of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
if (ret < 0 && pdata && pdata->bus_speed)
bus_speed = pdata->bus_speed;
of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
if (pdev->dev.of_node)
priv->devtype = (long)of_match_device(rcar_i2c_dt_ids,
dev)->data;
else
priv->devtype = platform_get_device_id(pdev)->driver_data;
priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
if (ret < 0)
@ -716,14 +711,6 @@ static int rcar_i2c_remove(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id rcar_i2c_id_table[] = {
{ "i2c-rcar", I2C_RCAR_GEN1 },
{ "i2c-rcar_gen1", I2C_RCAR_GEN1 },
{ "i2c-rcar_gen2", I2C_RCAR_GEN2 },
{},
};
MODULE_DEVICE_TABLE(platform, rcar_i2c_id_table);
static struct platform_driver rcar_i2c_driver = {
.driver = {
.name = "i2c-rcar",
@ -731,7 +718,6 @@ static struct platform_driver rcar_i2c_driver = {
},
.probe = rcar_i2c_probe,
.remove = rcar_i2c_remove,
.id_table = rcar_i2c_id_table,
};
module_platform_driver(rcar_i2c_driver);

View File

@ -858,6 +858,7 @@ static const struct of_device_id rk3x_i2c_match[] = {
{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
{},
};
MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
static int rk3x_i2c_probe(struct platform_device *pdev)
{

View File

@ -836,6 +836,7 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
{},
};

View File

@ -358,11 +358,29 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
if (err < 0)
bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
if (bitrate < 100000)
regval =
(2 * ctrl_speed) / (bitrate * 11);
else
/*
* Due to some hardware design issues, we need to tune the formula.
* Since i2c is open drain interface that allows the slave to
* stall the transaction by holding the SCL line at '0', the RTL
* implementation is waiting for SCL feedback from the pin after
* setting it to High-Z ('1'). This wait adds to the high-time
* interval counter few cycles of the input synchronization
* (depending on the SCL_FILTER_REG field), and also the time it
* takes for the board pull-up resistor to rise the SCL line.
* For slow SCL settings these additions are negligible,
* but they start to affect the speed when clock is set to faster
* frequencies.
* Through the actual tests, use the different user_div value(which
* in the divider formular 'Fio / (Fi2c * user_div)') to adapt
* the different ranges of i2c bus clock frequency, to make the SCL
* more accurate.
*/
if (bitrate <= 30000)
regval = ctrl_speed / (bitrate * 5);
else if (bitrate > 30000 && bitrate <= 280000)
regval = (2 * ctrl_speed) / (bitrate * 11);
else
regval = ctrl_speed / (bitrate * 6);
writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
if (regval > 0xFF)

View File

@ -977,6 +977,7 @@ static const struct of_device_id stu300_dt_match[] = {
{ .compatible = "st,ddci2c" },
{},
};
MODULE_DEVICE_TABLE(of, stu300_dt_match);
static struct platform_driver stu300_i2c_driver = {
.driver = {

View File

@ -873,7 +873,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->adapter.class = I2C_CLASS_DEPRECATED;
strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
sizeof(i2c_dev->adapter.name));
i2c_dev->adapter.algo = &tegra_i2c_algo;
i2c_dev->adapter.dev.parent = &pdev->dev;
i2c_dev->adapter.nr = pdev->id;
i2c_dev->adapter.dev.of_node = pdev->dev.of_node;

View File

@ -0,0 +1,584 @@
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#define UNIPHIER_FI2C_CR 0x00 /* control register */
#define UNIPHIER_FI2C_CR_MST BIT(3) /* master mode */
#define UNIPHIER_FI2C_CR_STA BIT(2) /* start condition */
#define UNIPHIER_FI2C_CR_STO BIT(1) /* stop condition */
#define UNIPHIER_FI2C_CR_NACK BIT(0) /* do not return ACK */
#define UNIPHIER_FI2C_DTTX 0x04 /* TX FIFO */
#define UNIPHIER_FI2C_DTTX_CMD BIT(8) /* send command (slave addr) */
#define UNIPHIER_FI2C_DTTX_RD BIT(0) /* read transaction */
#define UNIPHIER_FI2C_DTRX 0x04 /* RX FIFO */
#define UNIPHIER_FI2C_SLAD 0x0c /* slave address */
#define UNIPHIER_FI2C_CYC 0x10 /* clock cycle control */
#define UNIPHIER_FI2C_LCTL 0x14 /* clock low period control */
#define UNIPHIER_FI2C_SSUT 0x18 /* restart/stop setup time control */
#define UNIPHIER_FI2C_DSUT 0x1c /* data setup time control */
#define UNIPHIER_FI2C_INT 0x20 /* interrupt status */
#define UNIPHIER_FI2C_IE 0x24 /* interrupt enable */
#define UNIPHIER_FI2C_IC 0x28 /* interrupt clear */
#define UNIPHIER_FI2C_INT_TE BIT(9) /* TX FIFO empty */
#define UNIPHIER_FI2C_INT_RF BIT(8) /* RX FIFO full */
#define UNIPHIER_FI2C_INT_TC BIT(7) /* send complete (STOP) */
#define UNIPHIER_FI2C_INT_RC BIT(6) /* receive complete (STOP) */
#define UNIPHIER_FI2C_INT_TB BIT(5) /* sent specified bytes */
#define UNIPHIER_FI2C_INT_RB BIT(4) /* received specified bytes */
#define UNIPHIER_FI2C_INT_NA BIT(2) /* no ACK */
#define UNIPHIER_FI2C_INT_AL BIT(1) /* arbitration lost */
#define UNIPHIER_FI2C_SR 0x2c /* status register */
#define UNIPHIER_FI2C_SR_DB BIT(12) /* device busy */
#define UNIPHIER_FI2C_SR_STS BIT(11) /* stop condition detected */
#define UNIPHIER_FI2C_SR_BB BIT(8) /* bus busy */
#define UNIPHIER_FI2C_SR_RFF BIT(3) /* RX FIFO full */
#define UNIPHIER_FI2C_SR_RNE BIT(2) /* RX FIFO not empty */
#define UNIPHIER_FI2C_SR_TNF BIT(1) /* TX FIFO not full */
#define UNIPHIER_FI2C_SR_TFE BIT(0) /* TX FIFO empty */
#define UNIPHIER_FI2C_RST 0x34 /* reset control */
#define UNIPHIER_FI2C_RST_TBRST BIT(2) /* clear TX FIFO */
#define UNIPHIER_FI2C_RST_RBRST BIT(1) /* clear RX FIFO */
#define UNIPHIER_FI2C_RST_RST BIT(0) /* forcible bus reset */
#define UNIPHIER_FI2C_BM 0x38 /* bus monitor */
#define UNIPHIER_FI2C_BM_SDAO BIT(3) /* output for SDA line */
#define UNIPHIER_FI2C_BM_SDAS BIT(2) /* readback of SDA line */
#define UNIPHIER_FI2C_BM_SCLO BIT(1) /* output for SCL line */
#define UNIPHIER_FI2C_BM_SCLS BIT(0) /* readback of SCL line */
#define UNIPHIER_FI2C_NOISE 0x3c /* noise filter control */
#define UNIPHIER_FI2C_TBC 0x40 /* TX byte count setting */
#define UNIPHIER_FI2C_RBC 0x44 /* RX byte count setting */
#define UNIPHIER_FI2C_TBCM 0x48 /* TX byte count monitor */
#define UNIPHIER_FI2C_RBCM 0x4c /* RX byte count monitor */
#define UNIPHIER_FI2C_BRST 0x50 /* bus reset */
#define UNIPHIER_FI2C_BRST_FOEN BIT(1) /* normal operation */
#define UNIPHIER_FI2C_BRST_RSCL BIT(0) /* release SCL */
#define UNIPHIER_FI2C_INT_FAULTS \
(UNIPHIER_FI2C_INT_NA | UNIPHIER_FI2C_INT_AL)
#define UNIPHIER_FI2C_INT_STOP \
(UNIPHIER_FI2C_INT_TC | UNIPHIER_FI2C_INT_RC)
#define UNIPHIER_FI2C_RD BIT(0)
#define UNIPHIER_FI2C_STOP BIT(1)
#define UNIPHIER_FI2C_MANUAL_NACK BIT(2)
#define UNIPHIER_FI2C_BYTE_WISE BIT(3)
#define UNIPHIER_FI2C_DEFER_STOP_COMP BIT(4)
#define UNIPHIER_FI2C_DEFAULT_SPEED 100000
#define UNIPHIER_FI2C_MAX_SPEED 400000
#define UNIPHIER_FI2C_FIFO_SIZE 8
struct uniphier_fi2c_priv {
struct completion comp;
struct i2c_adapter adap;
void __iomem *membase;
struct clk *clk;
unsigned int len;
u8 *buf;
u32 enabled_irqs;
int error;
unsigned int flags;
unsigned int busy_cnt;
};
static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
bool first)
{
int fifo_space = UNIPHIER_FI2C_FIFO_SIZE;
/*
* TX-FIFO stores slave address in it for the first access.
* Decrement the counter.
*/
if (first)
fifo_space--;
while (priv->len) {
if (fifo_space-- <= 0)
break;
dev_dbg(&priv->adap.dev, "write data: %02x\n", *priv->buf);
writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX);
priv->len--;
}
}
static void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv)
{
int fifo_left = priv->flags & UNIPHIER_FI2C_BYTE_WISE ?
1 : UNIPHIER_FI2C_FIFO_SIZE;
while (priv->len) {
if (fifo_left-- <= 0)
break;
*priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX);
dev_dbg(&priv->adap.dev, "read data: %02x\n", priv->buf[-1]);
priv->len--;
}
}
static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
{
writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
}
static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv)
{
writel(-1, priv->membase + UNIPHIER_FI2C_IC);
}
static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
{
dev_dbg(&priv->adap.dev, "stop condition\n");
priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP;
uniphier_fi2c_set_irqs(priv);
writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO,
priv->membase + UNIPHIER_FI2C_CR);
}
static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
{
struct uniphier_fi2c_priv *priv = dev_id;
u32 irq_status;
irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
dev_dbg(&priv->adap.dev,
"interrupt: enabled_irqs=%04x, irq_status=%04x\n",
priv->enabled_irqs, irq_status);
if (irq_status & UNIPHIER_FI2C_INT_STOP)
goto complete;
if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) {
dev_dbg(&priv->adap.dev, "arbitration lost\n");
priv->error = -EAGAIN;
goto complete;
}
if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) {
dev_dbg(&priv->adap.dev, "could not get ACK\n");
priv->error = -ENXIO;
if (priv->flags & UNIPHIER_FI2C_RD) {
/*
* work around a hardware bug:
* The receive-completed interrupt is never set even if
* STOP condition is detected after the address phase
* of read transaction fails to get ACK.
* To avoid time-out error, we issue STOP here,
* but do not wait for its completion.
* It should be checked after exiting this handler.
*/
uniphier_fi2c_stop(priv);
priv->flags |= UNIPHIER_FI2C_DEFER_STOP_COMP;
goto complete;
}
goto stop;
}
if (irq_status & UNIPHIER_FI2C_INT_TE) {
if (!priv->len)
goto data_done;
uniphier_fi2c_fill_txfifo(priv, false);
goto handled;
}
if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) {
uniphier_fi2c_drain_rxfifo(priv);
if (!priv->len)
goto data_done;
if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) {
if (priv->len <= UNIPHIER_FI2C_FIFO_SIZE &&
!(priv->flags & UNIPHIER_FI2C_BYTE_WISE)) {
dev_dbg(&priv->adap.dev,
"enable read byte count IRQ\n");
priv->enabled_irqs |= UNIPHIER_FI2C_INT_RB;
uniphier_fi2c_set_irqs(priv);
priv->flags |= UNIPHIER_FI2C_BYTE_WISE;
}
if (priv->len <= 1) {
dev_dbg(&priv->adap.dev, "set NACK\n");
writel(UNIPHIER_FI2C_CR_MST |
UNIPHIER_FI2C_CR_NACK,
priv->membase + UNIPHIER_FI2C_CR);
}
}
goto handled;
}
return IRQ_NONE;
data_done:
if (priv->flags & UNIPHIER_FI2C_STOP) {
stop:
uniphier_fi2c_stop(priv);
} else {
complete:
priv->enabled_irqs = 0;
uniphier_fi2c_set_irqs(priv);
complete(&priv->comp);
}
handled:
uniphier_fi2c_clear_irqs(priv);
return IRQ_HANDLED;
}
static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
{
priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
/* do not use TX byte counter */
writel(0, priv->membase + UNIPHIER_FI2C_TBC);
/* set slave address */
writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1,
priv->membase + UNIPHIER_FI2C_DTTX);
/* first chunk of data */
uniphier_fi2c_fill_txfifo(priv, true);
}
static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
{
priv->flags |= UNIPHIER_FI2C_RD;
if (likely(priv->len < 256)) {
/*
* If possible, use RX byte counter.
* It can automatically handle NACK for the last byte.
*/
writel(priv->len, priv->membase + UNIPHIER_FI2C_RBC);
priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF |
UNIPHIER_FI2C_INT_RB;
} else {
/*
* The byte counter can not count over 256. In this case,
* do not use it at all. Drain data when FIFO gets full,
* but treat the last portion as a special case.
*/
writel(0, priv->membase + UNIPHIER_FI2C_RBC);
priv->flags |= UNIPHIER_FI2C_MANUAL_NACK;
priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF;
}
/* set slave address with RD bit */
writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1,
priv->membase + UNIPHIER_FI2C_DTTX);
}
static void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv)
{
writel(UNIPHIER_FI2C_RST_RST, priv->membase + UNIPHIER_FI2C_RST);
}
static void uniphier_fi2c_prepare_operation(struct uniphier_fi2c_priv *priv)
{
writel(UNIPHIER_FI2C_BRST_FOEN | UNIPHIER_FI2C_BRST_RSCL,
priv->membase + UNIPHIER_FI2C_BRST);
}
static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv)
{
uniphier_fi2c_reset(priv);
i2c_recover_bus(&priv->adap);
}
static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
struct i2c_msg *msg, bool stop)
{
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
bool is_read = msg->flags & I2C_M_RD;
unsigned long time_left;
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
priv->len = msg->len;
priv->buf = msg->buf;
priv->enabled_irqs = UNIPHIER_FI2C_INT_FAULTS;
priv->error = 0;
priv->flags = 0;
if (stop)
priv->flags |= UNIPHIER_FI2C_STOP;
reinit_completion(&priv->comp);
uniphier_fi2c_clear_irqs(priv);
writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST,
priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */
if (is_read)
uniphier_fi2c_rx_init(priv, msg->addr);
else
uniphier_fi2c_tx_init(priv, msg->addr);
uniphier_fi2c_set_irqs(priv);
dev_dbg(&adap->dev, "start condition\n");
writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
priv->membase + UNIPHIER_FI2C_CR);
time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
if (!time_left) {
dev_err(&adap->dev, "transaction timeout.\n");
uniphier_fi2c_recover(priv);
return -ETIMEDOUT;
}
dev_dbg(&adap->dev, "complete\n");
if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) {
u32 status = readl(priv->membase + UNIPHIER_FI2C_SR);
if (!(status & UNIPHIER_FI2C_SR_STS) ||
status & UNIPHIER_FI2C_SR_BB) {
dev_err(&adap->dev,
"stop condition was not completed.\n");
uniphier_fi2c_recover(priv);
return -EBUSY;
}
}
return priv->error;
}
static int uniphier_fi2c_check_bus_busy(struct i2c_adapter *adap)
{
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
if (readl(priv->membase + UNIPHIER_FI2C_SR) & UNIPHIER_FI2C_SR_DB) {
if (priv->busy_cnt++ > 3) {
/*
* If bus busy continues too long, it is probably
* in a wrong state. Try bus recovery.
*/
uniphier_fi2c_recover(priv);
priv->busy_cnt = 0;
}
return -EAGAIN;
}
priv->busy_cnt = 0;
return 0;
}
static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct i2c_msg *msg, *emsg = msgs + num;
int ret;
ret = uniphier_fi2c_check_bus_busy(adap);
if (ret)
return ret;
for (msg = msgs; msg < emsg; msg++) {
/* If next message is read, skip the stop condition */
bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
/* but, force it if I2C_M_STOP is set */
if (msg->flags & I2C_M_STOP)
stop = true;
ret = uniphier_fi2c_master_xfer_one(adap, msg, stop);
if (ret)
return ret;
}
return num;
}
static u32 uniphier_fi2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm uniphier_fi2c_algo = {
.master_xfer = uniphier_fi2c_master_xfer,
.functionality = uniphier_fi2c_functionality,
};
static int uniphier_fi2c_get_scl(struct i2c_adapter *adap)
{
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
UNIPHIER_FI2C_BM_SCLS);
}
static void uniphier_fi2c_set_scl(struct i2c_adapter *adap, int val)
{
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
writel(val ? UNIPHIER_FI2C_BRST_RSCL : 0,
priv->membase + UNIPHIER_FI2C_BRST);
}
static int uniphier_fi2c_get_sda(struct i2c_adapter *adap)
{
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
UNIPHIER_FI2C_BM_SDAS);
}
static void uniphier_fi2c_unprepare_recovery(struct i2c_adapter *adap)
{
uniphier_fi2c_prepare_operation(i2c_get_adapdata(adap));
}
static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = {
.recover_bus = i2c_generic_scl_recovery,
.get_scl = uniphier_fi2c_get_scl,
.set_scl = uniphier_fi2c_set_scl,
.get_sda = uniphier_fi2c_get_sda,
.unprepare_recovery = uniphier_fi2c_unprepare_recovery,
};
static int uniphier_fi2c_clk_init(struct device *dev,
struct uniphier_fi2c_priv *priv)
{
struct device_node *np = dev->of_node;
unsigned long clk_rate;
u32 bus_speed, clk_count;
int ret;
if (of_property_read_u32(np, "clock-frequency", &bus_speed))
bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
if (bus_speed > UNIPHIER_FI2C_MAX_SPEED)
bus_speed = UNIPHIER_FI2C_MAX_SPEED;
/* Get input clk rate through clk driver */
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
clk_rate = clk_get_rate(priv->clk);
uniphier_fi2c_reset(priv);
clk_count = clk_rate / bus_speed;
writel(clk_count, priv->membase + UNIPHIER_FI2C_CYC);
writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_LCTL);
writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_SSUT);
writel(clk_count / 16, priv->membase + UNIPHIER_FI2C_DSUT);
uniphier_fi2c_prepare_operation(priv);
return 0;
}
static int uniphier_fi2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct uniphier_fi2c_priv *priv;
struct resource *regs;
int irq;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->membase = devm_ioremap_resource(dev, regs);
if (IS_ERR(priv->membase))
return PTR_ERR(priv->membase);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "failed to get IRQ number");
return irq;
}
init_completion(&priv->comp);
priv->adap.owner = THIS_MODULE;
priv->adap.algo = &uniphier_fi2c_algo;
priv->adap.dev.parent = dev;
priv->adap.dev.of_node = dev->of_node;
strlcpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name));
priv->adap.bus_recovery_info = &uniphier_fi2c_bus_recovery_info;
i2c_set_adapdata(&priv->adap, priv);
platform_set_drvdata(pdev, priv);
ret = uniphier_fi2c_clk_init(dev, priv);
if (ret)
return ret;
ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
pdev->name, priv);
if (ret) {
dev_err(dev, "failed to request irq %d\n", irq);
goto err;
}
ret = i2c_add_adapter(&priv->adap);
if (ret) {
dev_err(dev, "failed to add I2C adapter\n");
goto err;
}
err:
if (ret)
clk_disable_unprepare(priv->clk);
return ret;
}
static int uniphier_fi2c_remove(struct platform_device *pdev)
{
struct uniphier_fi2c_priv *priv = platform_get_drvdata(pdev);
i2c_del_adapter(&priv->adap);
clk_disable_unprepare(priv->clk);
return 0;
}
static const struct of_device_id uniphier_fi2c_match[] = {
{ .compatible = "socionext,uniphier-fi2c" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, uniphier_fi2c_match);
static struct platform_driver uniphier_fi2c_drv = {
.probe = uniphier_fi2c_probe,
.remove = uniphier_fi2c_remove,
.driver = {
.name = "uniphier-fi2c",
.of_match_table = uniphier_fi2c_match,
},
};
module_platform_driver(uniphier_fi2c_drv);
MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
MODULE_DESCRIPTION("UniPhier FIFO-builtin I2C bus driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,441 @@
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#define UNIPHIER_I2C_DTRM 0x00 /* TX register */
#define UNIPHIER_I2C_DTRM_IRQEN BIT(11) /* enable interrupt */
#define UNIPHIER_I2C_DTRM_STA BIT(10) /* start condition */
#define UNIPHIER_I2C_DTRM_STO BIT(9) /* stop condition */
#define UNIPHIER_I2C_DTRM_NACK BIT(8) /* do not return ACK */
#define UNIPHIER_I2C_DTRM_RD BIT(0) /* read transaction */
#define UNIPHIER_I2C_DREC 0x04 /* RX register */
#define UNIPHIER_I2C_DREC_MST BIT(14) /* 1 = master, 0 = slave */
#define UNIPHIER_I2C_DREC_TX BIT(13) /* 1 = transmit, 0 = receive */
#define UNIPHIER_I2C_DREC_STS BIT(12) /* stop condition detected */
#define UNIPHIER_I2C_DREC_LRB BIT(11) /* no ACK */
#define UNIPHIER_I2C_DREC_LAB BIT(9) /* arbitration lost */
#define UNIPHIER_I2C_DREC_BBN BIT(8) /* bus not busy */
#define UNIPHIER_I2C_MYAD 0x08 /* slave address */
#define UNIPHIER_I2C_CLK 0x0c /* clock frequency control */
#define UNIPHIER_I2C_BRST 0x10 /* bus reset */
#define UNIPHIER_I2C_BRST_FOEN BIT(1) /* normal operation */
#define UNIPHIER_I2C_BRST_RSCL BIT(0) /* release SCL */
#define UNIPHIER_I2C_HOLD 0x14 /* hold time control */
#define UNIPHIER_I2C_BSTS 0x18 /* bus status monitor */
#define UNIPHIER_I2C_BSTS_SDA BIT(1) /* readback of SDA line */
#define UNIPHIER_I2C_BSTS_SCL BIT(0) /* readback of SCL line */
#define UNIPHIER_I2C_NOISE 0x1c /* noise filter control */
#define UNIPHIER_I2C_SETUP 0x20 /* setup time control */
#define UNIPHIER_I2C_DEFAULT_SPEED 100000
#define UNIPHIER_I2C_MAX_SPEED 400000
struct uniphier_i2c_priv {
struct completion comp;
struct i2c_adapter adap;
void __iomem *membase;
struct clk *clk;
unsigned int busy_cnt;
};
static irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id)
{
struct uniphier_i2c_priv *priv = dev_id;
/*
* This hardware uses edge triggered interrupt. Do not touch the
* hardware registers in this handler to make sure to catch the next
* interrupt edge. Just send a complete signal and return.
*/
complete(&priv->comp);
return IRQ_HANDLED;
}
static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
u32 *rxdatap)
{
struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
unsigned long time_left;
u32 rxdata;
reinit_completion(&priv->comp);
txdata |= UNIPHIER_I2C_DTRM_IRQEN;
dev_dbg(&adap->dev, "write data: 0x%04x\n", txdata);
writel(txdata, priv->membase + UNIPHIER_I2C_DTRM);
time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
if (unlikely(!time_left)) {
dev_err(&adap->dev, "transaction timeout\n");
return -ETIMEDOUT;
}
rxdata = readl(priv->membase + UNIPHIER_I2C_DREC);
dev_dbg(&adap->dev, "read data: 0x%04x\n", rxdata);
if (rxdatap)
*rxdatap = rxdata;
return 0;
}
static int uniphier_i2c_send_byte(struct i2c_adapter *adap, u32 txdata)
{
u32 rxdata;
int ret;
ret = uniphier_i2c_xfer_byte(adap, txdata, &rxdata);
if (ret)
return ret;
if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB)) {
dev_dbg(&adap->dev, "arbitration lost\n");
return -EAGAIN;
}
if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB)) {
dev_dbg(&adap->dev, "could not get ACK\n");
return -ENXIO;
}
return 0;
}
static int uniphier_i2c_tx(struct i2c_adapter *adap, u16 addr, u16 len,
const u8 *buf)
{
int ret;
dev_dbg(&adap->dev, "start condition\n");
ret = uniphier_i2c_send_byte(adap, addr << 1 |
UNIPHIER_I2C_DTRM_STA |
UNIPHIER_I2C_DTRM_NACK);
if (ret)
return ret;
while (len--) {
ret = uniphier_i2c_send_byte(adap,
UNIPHIER_I2C_DTRM_NACK | *buf++);
if (ret)
return ret;
}
return 0;
}
static int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len,
u8 *buf)
{
int ret;
dev_dbg(&adap->dev, "start condition\n");
ret = uniphier_i2c_send_byte(adap, addr << 1 |
UNIPHIER_I2C_DTRM_STA |
UNIPHIER_I2C_DTRM_NACK |
UNIPHIER_I2C_DTRM_RD);
if (ret)
return ret;
while (len--) {
u32 rxdata;
ret = uniphier_i2c_xfer_byte(adap,
len ? 0 : UNIPHIER_I2C_DTRM_NACK,
&rxdata);
if (ret)
return ret;
*buf++ = rxdata;
}
return 0;
}
static int uniphier_i2c_stop(struct i2c_adapter *adap)
{
dev_dbg(&adap->dev, "stop condition\n");
return uniphier_i2c_send_byte(adap, UNIPHIER_I2C_DTRM_STO |
UNIPHIER_I2C_DTRM_NACK);
}
static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
struct i2c_msg *msg, bool stop)
{
bool is_read = msg->flags & I2C_M_RD;
bool recovery = false;
int ret;
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
if (is_read)
ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf);
else
ret = uniphier_i2c_tx(adap, msg->addr, msg->len, msg->buf);
if (ret == -EAGAIN) /* could not acquire bus. bail out without STOP */
return ret;
if (ret == -ETIMEDOUT) {
/* This error is fatal. Needs recovery. */
stop = false;
recovery = true;
}
if (stop) {
int ret2 = uniphier_i2c_stop(adap);
if (ret2) {
/* Failed to issue STOP. The bus needs recovery. */
recovery = true;
ret = ret ?: ret2;
}
}
if (recovery)
i2c_recover_bus(adap);
return ret;
}
static int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap)
{
struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
if (!(readl(priv->membase + UNIPHIER_I2C_DREC) &
UNIPHIER_I2C_DREC_BBN)) {
if (priv->busy_cnt++ > 3) {
/*
* If bus busy continues too long, it is probably
* in a wrong state. Try bus recovery.
*/
i2c_recover_bus(adap);
priv->busy_cnt = 0;
}
return -EAGAIN;
}
priv->busy_cnt = 0;
return 0;
}
static int uniphier_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct i2c_msg *msg, *emsg = msgs + num;
int ret;
ret = uniphier_i2c_check_bus_busy(adap);
if (ret)
return ret;
for (msg = msgs; msg < emsg; msg++) {
/* If next message is read, skip the stop condition */
bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
/* but, force it if I2C_M_STOP is set */
if (msg->flags & I2C_M_STOP)
stop = true;
ret = uniphier_i2c_master_xfer_one(adap, msg, stop);
if (ret)
return ret;
}
return num;
}
static u32 uniphier_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm uniphier_i2c_algo = {
.master_xfer = uniphier_i2c_master_xfer,
.functionality = uniphier_i2c_functionality,
};
static void uniphier_i2c_reset(struct uniphier_i2c_priv *priv, bool reset_on)
{
u32 val = UNIPHIER_I2C_BRST_RSCL;
val |= reset_on ? 0 : UNIPHIER_I2C_BRST_FOEN;
writel(val, priv->membase + UNIPHIER_I2C_BRST);
}
static int uniphier_i2c_get_scl(struct i2c_adapter *adap)
{
struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
UNIPHIER_I2C_BSTS_SCL);
}
static void uniphier_i2c_set_scl(struct i2c_adapter *adap, int val)
{
struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
writel(val ? UNIPHIER_I2C_BRST_RSCL : 0,
priv->membase + UNIPHIER_I2C_BRST);
}
static int uniphier_i2c_get_sda(struct i2c_adapter *adap)
{
struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
UNIPHIER_I2C_BSTS_SDA);
}
static void uniphier_i2c_unprepare_recovery(struct i2c_adapter *adap)
{
uniphier_i2c_reset(i2c_get_adapdata(adap), false);
}
static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = {
.recover_bus = i2c_generic_scl_recovery,
.get_scl = uniphier_i2c_get_scl,
.set_scl = uniphier_i2c_set_scl,
.get_sda = uniphier_i2c_get_sda,
.unprepare_recovery = uniphier_i2c_unprepare_recovery,
};
static int uniphier_i2c_clk_init(struct device *dev,
struct uniphier_i2c_priv *priv)
{
struct device_node *np = dev->of_node;
unsigned long clk_rate;
u32 bus_speed;
int ret;
if (of_property_read_u32(np, "clock-frequency", &bus_speed))
bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
if (bus_speed > UNIPHIER_I2C_MAX_SPEED)
bus_speed = UNIPHIER_I2C_MAX_SPEED;
/* Get input clk rate through clk driver */
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
clk_rate = clk_get_rate(priv->clk);
uniphier_i2c_reset(priv, true);
writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed),
priv->membase + UNIPHIER_I2C_CLK);
uniphier_i2c_reset(priv, false);
return 0;
}
static int uniphier_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct uniphier_i2c_priv *priv;
struct resource *regs;
int irq;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->membase = devm_ioremap_resource(dev, regs);
if (IS_ERR(priv->membase))
return PTR_ERR(priv->membase);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "failed to get IRQ number");
return irq;
}
init_completion(&priv->comp);
priv->adap.owner = THIS_MODULE;
priv->adap.algo = &uniphier_i2c_algo;
priv->adap.dev.parent = dev;
priv->adap.dev.of_node = dev->of_node;
strlcpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name));
priv->adap.bus_recovery_info = &uniphier_i2c_bus_recovery_info;
i2c_set_adapdata(&priv->adap, priv);
platform_set_drvdata(pdev, priv);
ret = uniphier_i2c_clk_init(dev, priv);
if (ret)
return ret;
ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
priv);
if (ret) {
dev_err(dev, "failed to request irq %d\n", irq);
goto err;
}
ret = i2c_add_adapter(&priv->adap);
if (ret) {
dev_err(dev, "failed to add I2C adapter\n");
goto err;
}
err:
if (ret)
clk_disable_unprepare(priv->clk);
return ret;
}
static int uniphier_i2c_remove(struct platform_device *pdev)
{
struct uniphier_i2c_priv *priv = platform_get_drvdata(pdev);
i2c_del_adapter(&priv->adap);
clk_disable_unprepare(priv->clk);
return 0;
}
static const struct of_device_id uniphier_i2c_match[] = {
{ .compatible = "socionext,uniphier-i2c" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, uniphier_i2c_match);
static struct platform_driver uniphier_i2c_drv = {
.probe = uniphier_i2c_probe,
.remove = uniphier_i2c_remove,
.driver = {
.name = "uniphier-i2c",
.of_match_table = uniphier_i2c_match,
},
};
module_platform_driver(uniphier_i2c_drv);
MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
MODULE_DESCRIPTION("UniPhier I2C bus driver");
MODULE_LICENSE("GPL");

View File

@ -99,27 +99,40 @@ struct gsb_buffer {
};
} __packed;
static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
struct acpi_i2c_lookup {
struct i2c_board_info *info;
acpi_handle adapter_handle;
acpi_handle device_handle;
};
static int acpi_i2c_find_address(struct acpi_resource *ares, void *data)
{
struct i2c_board_info *info = data;
struct acpi_i2c_lookup *lookup = data;
struct i2c_board_info *info = lookup->info;
struct acpi_resource_i2c_serialbus *sb;
acpi_handle adapter_handle;
acpi_status status;
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
struct acpi_resource_i2c_serialbus *sb;
if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
return 1;
sb = &ares->data.i2c_serial_bus;
if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
info->addr = sb->slave_address;
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN;
}
} else if (!info->irq) {
struct resource r;
sb = &ares->data.i2c_serial_bus;
if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
return 1;
if (acpi_dev_resource_interrupt(ares, 0, &r))
info->irq = r.start;
/*
* Extract the ResourceSource and make sure that the handle matches
* with the I2C adapter handle.
*/
status = acpi_get_handle(lookup->device_handle,
sb->resource_source.string_ptr,
&adapter_handle);
if (ACPI_SUCCESS(status) && adapter_handle == lookup->adapter_handle) {
info->addr = sb->slave_address;
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN;
}
/* Tell the ACPI core to skip this resource */
return 1;
}
@ -128,6 +141,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
{
struct i2c_adapter *adapter = data;
struct list_head resource_list;
struct acpi_i2c_lookup lookup;
struct resource_entry *entry;
struct i2c_board_info info;
struct acpi_device *adev;
int ret;
@ -140,14 +155,37 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
memset(&info, 0, sizeof(info));
info.fwnode = acpi_fwnode_handle(adev);
memset(&lookup, 0, sizeof(lookup));
lookup.adapter_handle = ACPI_HANDLE(&adapter->dev);
lookup.device_handle = handle;
lookup.info = &info;
/*
* Look up for I2cSerialBus resource with ResourceSource that
* matches with this adapter.
*/
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
acpi_i2c_add_resource, &info);
acpi_i2c_find_address, &lookup);
acpi_dev_free_resource_list(&resource_list);
if (ret < 0 || !info.addr)
return AE_OK;
/* Then fill IRQ number if any */
ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (ret < 0)
return AE_OK;
resource_list_for_each_entry(entry, &resource_list) {
if (resource_type(entry->res) == IORESOURCE_IRQ) {
info.irq = entry->res->start;
break;
}
}
acpi_dev_free_resource_list(&resource_list);
adev->power.flags.ignore_parent = true;
strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
if (!i2c_new_device(adapter, &info)) {
@ -160,6 +198,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
return AE_OK;
}
#define ACPI_I2C_MAX_SCAN_DEPTH 32
/**
* acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
* @adap: pointer to adapter
@ -170,17 +210,13 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
*/
static void acpi_i2c_register_devices(struct i2c_adapter *adap)
{
acpi_handle handle;
acpi_status status;
if (!adap->dev.parent)
if (!has_acpi_companion(&adap->dev))
return;
handle = ACPI_HANDLE(adap->dev.parent);
if (!handle)
return;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_I2C_MAX_SCAN_DEPTH,
acpi_i2c_add_device, NULL,
adap, NULL);
if (ACPI_FAILURE(status))

View File

@ -235,7 +235,7 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
return result;
}
static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
unsigned long arg)
{
struct i2c_rdwr_ioctl_data rdwr_arg;
@ -250,7 +250,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
return -EINVAL;
rdwr_pa = memdup_user(rdwr_arg.msgs,
@ -421,16 +421,6 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case I2C_SLAVE:
case I2C_SLAVE_FORCE:
/* NOTE: devices set up to work with "new style" drivers
* can't use I2C_SLAVE, even when the device node is not
* bound to a driver. Only I2C_SLAVE_FORCE will work.
*
* Setting the PEC flag here won't affect kernel drivers,
* which will be using the i2c_client node registered with
* the driver model core. Likewise, when that client has
* the PEC flag already set, the i2c-dev driver won't see
* (or use) this setting.
*/
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
@ -446,6 +436,13 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC:
/*
* Setting the PEC flag here won't affect kernel drivers,
* which will be using the i2c_client node registered with
* the driver model core. Likewise, when that client has
* the PEC flag already set, the i2c-dev driver won't see
* (or use) this setting.
*/
if (arg)
client->flags |= I2C_CLIENT_PEC;
else
@ -456,7 +453,7 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR:
return i2cdev_ioctl_rdrw(client, arg);
return i2cdev_ioctl_rdwr(client, arg);
case I2C_SMBUS:
return i2cdev_ioctl_smbus(client, arg);

View File

@ -25,6 +25,7 @@
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/of.h>
#include <linux/acpi.h>
/* multiplexer per channel data */
struct i2c_mux_priv {
@ -173,6 +174,13 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
}
}
/*
* Associate the mux channel with an ACPI node.
*/
if (has_acpi_companion(mux_dev))
acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
chan_id);
if (force_nr) {
priv->adap.nr = force_nr;
ret = i2c_add_numbered_adapter(&priv->adap);

View File

@ -686,7 +686,7 @@ static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
if (get_user(nmsgs, &udata->nmsgs))
return -EFAULT;
if (nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
if (nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
return -EINVAL;
if (get_user(datap, &udata->msgs))

View File

@ -514,6 +514,11 @@ static inline bool has_acpi_companion(struct device *dev)
return false;
}
static inline void acpi_preset_companion(struct device *dev,
struct acpi_device *parent, u64 addr)
{
}
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;

View File

@ -15,6 +15,7 @@ struct ocores_i2c_platform_data {
u32 reg_shift; /* register offset shift value */
u32 reg_io_width; /* register io read/write width */
u32 clock_khz; /* input clock in kHz */
bool big_endian; /* registers are big endian */
u8 num_devices; /* number of devices in the devices list */
struct i2c_board_info const *devices; /* devices connected to the bus */
};

View File

@ -1,10 +0,0 @@
#ifndef __I2C_R_CAR_H__
#define __I2C_R_CAR_H__
#include <linux/platform_device.h>
struct i2c_rcar_platform_data {
u32 bus_speed;
};
#endif /* __I2C_R_CAR_H__ */

View File

@ -66,7 +66,9 @@ struct i2c_rdwr_ioctl_data {
__u32 nmsgs; /* number of i2c_msgs */
};
#define I2C_RDRW_IOCTL_MAX_MSGS 42
#define I2C_RDWR_IOCTL_MAX_MSGS 42
/* Originally defined with a typo, keep it for compatibility */
#define I2C_RDRW_IOCTL_MAX_MSGS I2C_RDWR_IOCTL_MAX_MSGS
#endif /* _UAPI_LINUX_I2C_DEV_H */