Commit 98f486f1 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull i2c updates from Wolfram Sang:
 - new drivers: Kontron PLD, Wondermedia VT
 - mv64xxx driver gained sun4i support and a bigger cleanup
 - duplicate driver 'intel-mid' removed
 - added generic device tree binding for sda holding time (and
   designware driver already uses it)
 - we tried to allow driver probing with only device tree and no i2c
   ids, but I had to revert it because of side effects.  Needs some
   rethinking.
 - driver bugfixes, cleanups...

* 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (34 commits)
  i2c-designware: use div_u64 to fix link
  i2c: Kontron PLD i2c bus driver
  i2c: iop3xxx: fix build failure after waitqueue changes
  i2c-designware: make SDA hold time configurable
  i2c: mv64xxx: Set bus frequency to 100kHz if clock-frequency is not provided
  i2c: imx: allow autoloading on dt ids
  i2c: mv64xxx: Fix transfer error code
  i2c: i801: SMBus patch for Intel Coleto Creek DeviceIDs
  i2c: omap: correct usage of the interrupt enable register
  i2c-pxa: prepare clock before use
  Revert "i2c: core: make it possible to match a pure device tree driver"
  i2c: nomadik: allocate adapter number dynamically
  i2c: nomadik: support elder Nomadiks
  i2c: mv64xxx: Add Allwinner sun4i compatible
  i2c: mv64xxx: make the registers offset configurable
  i2c: mv64xxx: Add macros to access parts of registers
  i2c: vt8500: Add support for I2C bus on Wondermedia SoCs
  i2c: designware: fix race between subsequent xfers
  i2c: bfin-twi: Read and write the FIFO in loop
  i2c: core: make it possible to match a pure device tree driver
  ...
parents 84cbd722 97191d73
......@@ -10,6 +10,10 @@ Recommended properties :
- clock-frequency : desired I2C bus clock frequency in Hz.
Optional properties :
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
This option is only supported in hardware blocks version 1.11a or newer.
Example :
i2c@f0000 {
......@@ -20,3 +24,14 @@ Example :
interrupts = <11>;
clock-frequency = <400000>;
};
i2c@1120000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,designware-i2c";
reg = <0x1120000 0x1000>;
interrupt-parent = <&ictl>;
interrupts = <12 1>;
clock-frequency = <400000>;
i2c-sda-hold-time-ns = <300>;
};
......@@ -6,7 +6,11 @@ Required properties :
- reg : Offset and length of the register set for the device
- compatible : Should be "marvell,mv64xxx-i2c"
- interrupts : The interrupt number
- clock-frequency : Desired I2C bus clock frequency in Hz.
Optional properties :
- clock-frequency : Desired I2C bus clock frequency in Hz. If not set the
default frequency is 100kHz
Examples:
......
* Wondermedia I2C Controller
Required properties :
- compatible : should be "wm,wm8505-i2c"
- reg : Offset and length of the register set for the device
- interrupts : <IRQ> where IRQ is the interrupt number
- clocks : phandle to the I2C clock source
Optional properties :
- clock-frequency : desired I2C bus clock frequency in Hz.
Valid values are 100000 and 400000.
Default to 100000 if not specified, or invalid value.
Example :
i2c_0: i2c@d8280000 {
compatible = "wm,wm8505-i2c";
reg = <0xd8280000 0x1000>;
interrupts = <19>;
clocks = <&clki2c0>;
clock-frequency = <400000>;
};
......@@ -24,6 +24,7 @@ Supported adapters:
* Intel Lynx Point-LP (PCH)
* Intel Avoton (SOC)
* Intel Wellsburg (PCH)
* Intel Coleto Creek (PCH)
Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller
......
......@@ -1301,6 +1301,7 @@ S: Maintained
F: arch/arm/mach-vt8500/
F: drivers/clocksource/vt8500_timer.c
F: drivers/gpio/gpio-vt8500.c
F: drivers/i2c/busses/i2c-wmt.c
F: drivers/mmc/host/wmt-sdmmc.c
F: drivers/pwm/pwm-vt8500.c
F: drivers/rtc/rtc-vt8500.c
......
......@@ -45,19 +45,19 @@ ethernet@FE100000 {
};
i2c0: i2c@FF120000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c1: i2c@FF121000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c2: i2c@FF122000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c3: i2c@FF123000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c4: i2c@FF124000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
leds {
......
......@@ -45,19 +45,19 @@ ethernet@FE100000 {
};
i2c0: i2c@FF120000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c1: i2c@FF121000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c2: i2c@FF122000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c3: i2c@FF123000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
i2c4: i2c@FF124000 {
sda-hold-time = <432>;
i2c-sda-hold-time-ns = <432>;
};
leds {
......
......@@ -108,6 +108,7 @@ config I2C_I801
Lynx Point-LP (PCH)
Avoton (SOC)
Wellsburg (PCH)
Coleto Creek (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
......@@ -475,16 +476,6 @@ config I2C_IMX
This driver can also be built as a module. If so, the module
will be called i2c-imx.
config I2C_INTEL_MID
tristate "Intel Moorestown/Medfield Platform I2C controller"
depends on PCI
help
Say Y here if you have an Intel Moorestown/Medfield platform I2C
controller.
This support is also available as a module. If so, the module
will be called i2c-intel-mid.
config I2C_IOP3XX
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
......@@ -495,6 +486,16 @@ config I2C_IOP3XX
This driver can also be built as a module. If so, the module
will be called i2c-iop3xx.
config I2C_KEMPLD
tristate "Kontron COM I2C Controller"
depends on MFD_KEMPLD
help
This enables support for the I2C bus interface on some Kontron ETX
and COMexpress (ETXexpress) modules.
This driver can also be built as a module. If so, the module
will be called i2c-kempld.
config I2C_MPC
tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC
......@@ -508,10 +509,11 @@ config I2C_MPC
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
depends on (MV64X60 || PLAT_ORION)
depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI)
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Marvell 64xxx line of host bridges.
This driver is also used for Allwinner SoCs I2C controllers.
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
......@@ -725,6 +727,16 @@ config I2C_VERSATILE
This driver can also be built as a module. If so, the module
will be called i2c-versatile.
config I2C_WMT
tristate "Wondermedia WM8xxx SoC I2C bus support"
depends on ARCH_VT8500
help
Say yes if you want to support the I2C bus on Wondermedia 8xxx-series
SoCs.
This driver can also be built as a module. If so, the module will be
called i2c-wmt.
config I2C_OCTEON
tristate "Cavium OCTEON I2C bus support"
depends on CPU_CAVIUM_OCTEON
......
......@@ -46,8 +46,8 @@ obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
......@@ -71,6 +71,7 @@ obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
......
......@@ -39,33 +39,40 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
unsigned short mast_stat = read_MASTER_STAT(iface);
if (twi_int_status & XMTSERV) {
if (iface->writeNum <= 0) {
/* start receive immediately after complete sending in
* combine mode.
*/
if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | MDIR);
else if (iface->manual_stop)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | STOP);
else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg + 1 < iface->msg_num) {
if (iface->pmsg[iface->cur_msg + 1].flags &
I2C_M_RD)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) |
MDIR);
else
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) &
~MDIR);
}
}
/* Transmit next data */
if (iface->writeNum > 0) {
while (iface->writeNum > 0 &&
(read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) {
SSYNC();
write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--;
}
/* start receive immediately after complete sending in
* combine mode.
*/
else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | MDIR);
else if (iface->manual_stop)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | STOP);
else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg + 1 < iface->msg_num) {
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | MDIR);
else
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) & ~MDIR);
}
}
if (twi_int_status & RCVSERV) {
if (iface->readNum > 0) {
while (iface->readNum > 0 &&
(read_FIFO_STAT(iface) & RCVSTAT)) {
/* Receive next data */
*(iface->transPtr) = read_RCV_DATA8(iface);
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
......
......@@ -654,7 +654,7 @@ static int cpm_i2c_probe(struct platform_device *ofdev)
cpm->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, cpm);
platform_set_drvdata(ofdev, cpm);
cpm->adap = cpm_ops;
i2c_set_adapdata(&cpm->adap, cpm);
......@@ -697,7 +697,7 @@ static int cpm_i2c_probe(struct platform_device *ofdev)
static int cpm_i2c_remove(struct platform_device *ofdev)
{
struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
struct cpm_i2c *cpm = platform_get_drvdata(ofdev);
i2c_del_adapter(&cpm->adap);
......
......@@ -646,13 +646,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
struct resource *mem, *irq;
int r;
/* NOTE: driver uses the static register mapping */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "no mem resource?\n");
return -ENODEV;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "no irq resource?\n");
......@@ -697,6 +690,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
return -ENODEV;
clk_prepare_enable(dev->clk);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base)) {
r = PTR_ERR(dev->base);
......
......@@ -67,9 +67,12 @@
#define DW_IC_STATUS 0x70
#define DW_IC_TXFLR 0x74
#define DW_IC_RXFLR 0x78
#define DW_IC_SDA_HOLD 0x7c
#define DW_IC_TX_ABRT_SOURCE 0x80
#define DW_IC_ENABLE_STATUS 0x9c
#define DW_IC_COMP_PARAM_1 0xf4
#define DW_IC_COMP_VERSION 0xf8
#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
#define DW_IC_COMP_TYPE 0xfc
#define DW_IC_COMP_TYPE_VALUE 0x44570140
......@@ -332,6 +335,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
/* Configure SDA Hold Time if required */
if (dev->sda_hold_time) {
reg = dw_readl(dev, DW_IC_COMP_VERSION);
if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
else
dev_warn(dev->dev,
"Hardware too old to adjust SDA hold time.");
}
/* Configure Tx/Rx FIFO threshold levels */
dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
dw_writel(dev, 0, DW_IC_RX_TL);
......@@ -580,14 +593,23 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
i2c_dw_xfer_init(dev);
/* wait for tx to complete */
ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
if (ret == 0) {
dev_err(dev->dev, "controller timed out\n");
/* i2c_dw_init implicitly disables the adapter */
i2c_dw_init(dev);
ret = -ETIMEDOUT;
goto done;
} else if (ret < 0)
goto done;
}
/*
* We must disable the adapter before unlocking the &dev->lock mutex
* below. Otherwise the hardware might continue generating interrupts
* which in turn causes a race condition with the following transfer.
* Needs some more investigation if the additional interrupts are
* a hardware bug or this driver doesn't handle them correctly yet.
*/
__i2c_dw_enable(dev, false);
if (dev->msg_err) {
ret = dev->msg_err;
......@@ -596,8 +618,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
/* no error */
if (likely(!dev->cmd_err)) {
/* Disable the adapter */
__i2c_dw_enable(dev, false);
ret = num;
goto done;
}
......
......@@ -90,6 +90,7 @@ struct dw_i2c_dev {
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
int rx_outstanding;
u32 sda_hold_time;
};
#define ACCESS_SWAP 0x00000001
......
......@@ -34,6 +34,7 @@
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
......@@ -87,13 +88,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
struct resource *mem;
int irq, r;
/* NOTE: driver uses the static register mapping */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "no mem resource?\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
......@@ -104,6 +98,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
......@@ -121,6 +116,16 @@ static int dw_i2c_probe(struct platform_device *pdev)
return PTR_ERR(dev->clk);
clk_prepare_enable(dev->clk);
if (pdev->dev.of_node) {
u32 ht = 0;
u32 ic_clk = dev->get_clk_rate_khz(dev);
of_property_read_u32(pdev->dev.of_node,
"i2c-sda-hold-time-ns", &ht);
dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
1000000);
}
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
......
......@@ -58,6 +58,7 @@
Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes
Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes
Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
Features supported by this driver:
Software PEC no
......@@ -169,6 +170,7 @@
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
......@@ -817,6 +819,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
{ 0, }
};
......
......@@ -705,7 +705,7 @@ static int iic_probe(struct platform_device *ofdev)
return -ENOMEM;
}
dev_set_drvdata(&ofdev->dev, dev);
platform_set_drvdata(ofdev, dev);
dev->vaddr = of_iomap(np, 0);
if (dev->vaddr == NULL) {
......@@ -782,7 +782,7 @@ static int iic_probe(struct platform_device *ofdev)
*/
static int iic_remove(struct platform_device *ofdev)
{
struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
struct ibm_iic_private *dev = platform_get_drvdata(ofdev);
i2c_del_adapter(&dev->adap);
......
......@@ -51,7 +51,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h>
/** Defines ********************************************************************
......@@ -148,6 +147,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
{
......@@ -493,24 +493,19 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
struct imx_i2c_struct *i2c_imx;
struct resource *res;
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
struct pinctrl *pinctrl;
void __iomem *base;
int irq, ret;
u32 bitrate;
dev_dbg(&pdev->dev, "<%s>\n", __func__);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "can't get device resources\n");
return -ENOENT;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "can't get irq number\n");
return -ENOENT;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
......@@ -535,12 +530,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->base = base;
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
dev_err(&pdev->dev, "can't get/select pinctrl\n");
return PTR_ERR(pinctrl);
}
/* Get I2C clock */
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_imx->clk)) {
......
/*
* Support for Moorestown/Medfield I2C chip
*
* Copyright (c) 2009 Intel Corporation.
* Copyright (c) 2009 Synopsys. Inc.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#define DRIVER_NAME "i2c-intel-mid"
#define VERSION "Version 0.5ac2"
#define PLATFORM "Moorestown/Medfield"
/* Tables use: 0 Moorestown, 1 Medfield */
#define NUM_PLATFORMS 2
enum platform_enum {
MOORESTOWN = 0,
MEDFIELD = 1,
};
enum mid_i2c_status {
STATUS_IDLE = 0,
STATUS_READ_START,
STATUS_READ_IN_PROGRESS,
STATUS_READ_SUCCESS,
STATUS_WRITE_START,
STATUS_WRITE_SUCCESS,
STATUS_XFER_ABORT,
STATUS_STANDBY
};
/**
* struct intel_mid_i2c_private - per device I²C context
* @adap: core i2c layer adapter information
* @dev: device reference for power management
* @base: register base
* @speed: speed mode for this port
* @complete: completion object for transaction wait
* @abort: reason for last abort
* @rx_buf: pointer into working receive buffer
* @rx_buf_len: receive buffer length
* @status: adapter state machine
* @msg: the message we are currently processing
* @platform: the MID device type we are part of
* @lock: transaction serialization
*
* We allocate one of these per device we discover, it holds the core
* i2c layer objects and the data we need to track privately.
*/
struct intel_mid_i2c_private {
struct i2c_adapter adap;
struct device *dev;
void __iomem *base;
int speed;
struct completion complete;
int abort;
u8 *rx_buf;
int rx_buf_len;
enum mid_i2c_status status;
struct i2c_msg *msg;
enum platform_enum platform;
struct mutex lock;
};
#define NUM_SPEEDS 3
#define ACTIVE 0
#define STANDBY 1
/* Control register */
#define IC_CON 0x00
#define SLV_DIS (1 << 6) /* Disable slave mode */
#define RESTART (1 << 5) /* Send a Restart condition */
#define ADDR_10BIT (1 << 4) /* 10-bit addressing */
#define STANDARD_MODE (1 << 1) /* standard mode */
#define FAST_MODE (2 << 1) /* fast mode */
#define HIGH_MODE (3 << 1) /* high speed mode */
#define MASTER_EN (1 << 0) /* Master mode */
/* Target address register */
#define IC_TAR 0x04
#define IC_TAR_10BIT_ADDR (1 << 12) /* 10-bit addressing */
#define IC_TAR_SPECIAL (1 << 11) /* Perform special I2C cmd */
#define IC_TAR_GC_OR_START (1 << 10) /* 0: Gerneral Call Address */
/* 1: START BYTE */
/* Slave Address Register */
#define IC_SAR 0x08 /* Not used in Master mode */
/* High Speed Master Mode Code Address Register */
#define IC_HS_MADDR 0x0c
/* Rx/Tx Data Buffer and Command Register */
#define IC_DATA_CMD 0x10
#define IC_RD (1 << 8) /* 1: Read 0: Write */
/* Standard Speed Clock SCL High Count Register */
#define IC_SS_SCL_HCNT 0x14
/* Standard Speed Clock SCL Low Count Register */
#define IC_SS_SCL_LCNT 0x18
/* Fast Speed Clock SCL High Count Register */
#define IC_FS_SCL_HCNT 0x1c
/* Fast Spedd Clock SCL Low Count Register */
#define IC_FS_SCL_LCNT 0x20
/* High Speed Clock SCL High Count Register */
#define IC_HS_SCL_HCNT 0x24
/* High Speed Clock SCL Low Count Register */
#define IC_HS_SCL_LCNT 0x28
/* Interrupt Status Register */
#define IC_INTR_STAT 0x2c /* Read only */
#define R_GEN_CALL (1 << 11)
#define R_START_DET (1 << 10)
#define R_STOP_DET (1 << 9)
#define R_ACTIVITY (1 << 8)
#define R_RX_DONE (1 << 7)
#define R_TX_ABRT (1 << 6)
#define R_RD_REQ (1 << 5)
#define R_TX_EMPTY (1 << 4)
#define R_TX_OVER (1 << 3)
#define R_RX_FULL (1 << 2)
#define R_RX_OVER (1 << 1)
#define R_RX_UNDER (1 << 0)
/* Interrupt Mask Register */
#define IC_INTR_MASK 0x30 /* Read and Write */
#define M_GEN_CALL (1 << 11)
#define M_START_DET (1 << 10)
#define M_STOP_DET (1 << 9)
#define M_ACTIVITY (1 << 8)
#define M_RX_DONE (1 << 7)
#define M_TX_ABRT (1 << 6)
#define M_RD_REQ (1 << 5)
#define M_TX_EMPTY (1 << 4)
#define M_TX_OVER (1 << 3)
#define M_RX_FULL (1 << 2)
#define M_RX_OVER (1 << 1)
#define M_RX_UNDER (1 << 0)
/* Raw Interrupt Status Register */
#define IC_RAW_INTR_STAT 0x34 /* Read Only */
#define GEN_CALL (1 << 11) /* General call */
#define START_DET (1 << 10) /* (RE)START occurred */
#define STOP_DET (1 << 9) /* STOP occurred */
#define ACTIVITY (1 << 8) /* Bus busy */
#define RX_DONE (1 << 7) /* Not used in Master mode */
#define TX_ABRT (1 << 6) /* Transmit Abort */
#define RD_REQ (1 << 5) /* Not used in Master mode */
#define TX_EMPTY (1 << 4) /* TX FIFO <= threshold */
#define TX_OVER (1 << 3) /* TX FIFO overflow */
#define RX_FULL (1 << 2) /* RX FIFO >= threshold */
#define RX_OVER (1 << 1) /* RX FIFO overflow */
#define RX_UNDER (1 << 0) /* RX FIFO empty */
/* Receive FIFO Threshold Register */
#define IC_RX_TL 0x38
/* Transmit FIFO Treshold Register */
#define IC_TX_TL 0x3c
/* Clear Combined and Individual Interrupt Register */
#define IC_CLR_INTR 0x40
#define CLR_INTR (1 << 0)
/* Clear RX_UNDER Interrupt Register */
#define IC_CLR_RX_UNDER 0x44
#define CLR_RX_UNDER (1 << 0)
/* Clear RX_OVER Interrupt Register */
#define IC_CLR_RX_OVER 0x48
#define CLR_RX_OVER (1 << 0)
/* Clear TX_OVER Interrupt Register */
#define IC_CLR_TX_OVER 0x4c
#define CLR_TX_OVER (1 << 0)
#define IC_CLR_RD_REQ 0x50
/* Clear TX_ABRT Interrupt Register */
#define IC_CLR_TX_ABRT 0x54
#define CLR_TX_ABRT (1 << 0)
#define IC_CLR_RX_DONE 0x58
/* Clear ACTIVITY Interrupt Register */
#define IC_CLR_ACTIVITY 0x5c
#define CLR_ACTIVITY (1 << 0)
/* Clear STOP_DET Interrupt Register */
#define IC_CLR_STOP_DET 0x60
#define CLR_STOP_DET (1 << 0)
/* Clear START_DET Interrupt Register */
#define IC_CLR_START_DET 0x64
#define CLR_START_DET (1 << 0)
/* Clear GEN_CALL Interrupt Register */
#define IC_CLR_GEN_CALL 0x68
#define CLR_GEN_CALL (1 << 0)
/* Enable Register */
#define IC_ENABLE 0x6c
#define ENABLE (1 << 0)
/* Status Register */
#define IC_STATUS 0x70 /* Read Only */
#define STAT_SLV_ACTIVITY (1 << 6) /* Slave not in idle */
#define STAT_MST_ACTIVITY (1 << 5) /* Master not in idle */
#define STAT_RFF (1 << 4) /* RX FIFO Full */
#define STAT_RFNE (1 << 3) /* RX FIFO Not Empty */
#define STAT_TFE (1 << 2) /* TX FIFO Empty */
#define STAT_TFNF (1 << 1) /* TX FIFO Not Full */
#define STAT_ACTIVITY (1 << 0) /* Activity Status */
/* Transmit FIFO Level Register */
#define IC_TXFLR 0x74 /* Read Only */
#define TXFLR (1 << 0) /* TX FIFO level */
/* Receive FIFO Level Register */
#define IC_RXFLR 0x78 /* Read Only */
#define RXFLR (1 << 0) /* RX FIFO level */
/* Transmit Abort Source Register */
#define IC_TX_ABRT_SOURCE 0x80
#define ABRT_SLVRD_INTX (1 << 15)
#define ABRT_SLV_ARBLOST (1 << 14)
#define ABRT_SLVFLUSH_TXFIFO (1 << 13)
#define ARB_LOST (1 << 12)
#define ABRT_MASTER_DIS (1 << 11)
#define ABRT_10B_RD_NORSTRT (1 << 10)
#define ABRT_SBYTE_NORSTRT (1 << 9)
#define ABRT_HS_NORSTRT (1 << 8)
#define ABRT_SBYTE_ACKDET (1 << 7)
#define ABRT_HS_ACKDET (1 << 6)
#define ABRT_GCALL_READ (1 << 5)
#define ABRT_GCALL_NOACK (1 << 4)
#define ABRT_TXDATA_NOACK (1 << 3)
#define ABRT_10ADDR2_NOACK (1 << 2)
#define ABRT_10ADDR1_NOACK (1 << 1)
#define ABRT_7B_ADDR_NOACK (1 << 0)
/* Enable Status Register */
#define IC_ENABLE_STATUS 0x9c
#define IC_EN (1 << 0) /* I2C in an enabled state */
/* Component Parameter Register 1*/
#define IC_COMP_PARAM_1 0xf4
#define APB_DATA_WIDTH (0x3 << 0)
/* added by xiaolin --begin */
#define SS_MIN_SCL_HIGH 4000
#define SS_MIN_SCL_LOW 4700
#define FS_MIN_SCL_HIGH 600
#define FS_MIN_SCL_LOW 1300
#define HS_MIN_SCL_HIGH_100PF 60
#define HS_MIN_SCL_LOW_100PF 120
#define STANDARD 0
#define FAST 1
#define HIGH 2
#define NUM_SPEEDS 3
static int speed_mode[6] = {
FAST,
FAST,
FAST,
STANDARD,
FAST,
FAST
};
static int ctl_num = 6;
module_param_array(speed_mode, int, &ctl_num, S_IRUGO);
MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)");
/**
* intel_mid_i2c_disable - Disable I2C controller
* @adap: struct pointer to i2c_adapter
*
* Return Value:
* 0 success
* -EBUSY if device is busy
* -ETIMEDOUT if i2c cannot be disabled within the given time
*
* I2C bus state should be checked prior to disabling the hardware. If bus is
* not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable
* I2C controller.
*/
static int intel_mid_i2c_disable(struct i2c_adapter *adap)
{
struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
int err = 0;
int count = 0;
int ret1, ret2;
static const u16 delay[NUM_SPEEDS] = {100, 25, 3};
/* Set IC_ENABLE to 0 */
writel(0, i2c->base + IC_ENABLE);
/* Check if device is busy */
dev_dbg(&adap->dev, "mrst i2c disable\n");
while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1)
|| (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) {
udelay(delay[i2c->speed]);
writel(0, i2c->base + IC_ENABLE);
dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n",
count, i2c->speed);
if (count++ > 10) {
err = -ETIMEDOUT;
break;
}
}
/* Clear all interrupts */
readl(i2c->base + IC_CLR_INTR);
readl(i2c->base + IC_CLR_STOP_DET);
readl(i2c->base + IC_CLR_START_DET);
readl(i2c->base + IC_CLR_ACTIVITY);
readl(i2c->base + IC_CLR_TX_ABRT);
readl(i2c->base + IC_CLR_RX_OVER);
readl(i2c->base + IC_CLR_RX_UNDER);
readl(i2c->base + IC_CLR_TX_OVER);
readl(i2c->base + IC_CLR_RX_DONE);
readl(i2c->base + IC_CLR_GEN_CALL);
/* Disable all interupts */
writel(0x0000, i2c->base + IC_INTR_MASK);
return err;
}
/**
* intel_mid_i2c_hwinit - Initialize the I2C hardware registers
* @dev: pci device struct pointer
*
* This function will be called in intel_mid_i2c_probe() before device
* registration.
*
* Return Values:
* 0 success
* -EBUSY i2c cannot be disabled
* -ETIMEDOUT i2c cannot be disabled
* -EFAULT If APB data width is not 32-bit wide
*
* I2C should be disabled prior to other register operation. If failed, an
* errno is returned. Mask and Clear all interrpts, this should be done at
* first. Set common registers which will not be modified during normal
* transfers, including: control register, FIFO threshold and clock freq.
* Check APB data width at last.
*/
static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c)
{
int err;
static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
{ 0x75, 0x15, 0x07 },
{ 0x04c, 0x10, 0x06 }
};
static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
{ 0x7C, 0x21, 0x0E },
{ 0x053, 0x19, 0x0F }
};
/* Disable i2c first */
err = intel_mid_i2c_disable(&i2c->adap);
if (err)
return err;
/*
* Setup clock frequency and speed mode
* Enable restart condition,
* enable master FSM, disable slave FSM,
* use target address when initiating transfer
*/
writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN,
i2c->base + IC_CON);
writel(hcnt[i2c->platform][i2c->speed],
i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3)));
writel(lcnt[i2c->platform][i2c->speed],
i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3)));
/* Set tranmit & receive FIFO threshold to zero */
writel(0x0, i2c->base + IC_RX_TL);
writel(0x0, i2c->base + IC_TX_TL);
return 0;
}
/**
* intel_mid_i2c_func - Return the supported three I2C operations.
* @adapter: i2c_adapter struct pointer
*/
static u32 intel_mid_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
}
/**
* intel_mid_i2c_address_neq - To check if the addresses for different i2c messages
* are equal.
* @p1: first i2c_msg
* @p2: second i2c_msg
*
* Return Values:
* 0 if addresses are equal
* 1 if not equal
*
* Within a single transfer, the I2C client may need to send its address more
* than once. So a check if the addresses match is needed.
*/
static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1,
const struct i2c_msg *p2)
{
if (p1->addr != p2->addr)
return 1;
if ((p1->flags ^ p2->flags) & I2C_M_TEN)
return 1;
return 0;
}
/**
* intel_mid_i2c_abort - To handle transfer abortions and print error messages.
* @adap: i2c_adapter struct pointer
*
* By reading register IC_TX_ABRT_SOURCE, various transfer errors can be
* distingushed. At present, no circumstances have been found out that
* multiple errors would be occurred simutaneously, so we simply use the
* register value directly.
*
* At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need
* a few extra steps)
*/
static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c)
{
/* Read about source register */
int abort = i2c->abort;
struct i2c_adapter *adap = &i2c->adap;
/* Single transfer error check:
* According to databook, TX/RX FIFOs would be flushed when
* the abort interrupt occurred.
*/
if (abort & ABRT_MASTER_DIS)
dev_err(&adap->dev,
"initiate master operation with master mode disabled.\n");
if (abort & ABRT_10B_RD_NORSTRT)
dev_err(&adap->dev,
"RESTART disabled and master sent READ cmd in 10-bit addressing.\n");
if (abort & ABRT_SBYTE_NORSTRT) {
dev_err(&adap->dev,
"RESTART disabled and user is trying to send START byte.\n");
writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE);
writel(RESTART, i2c->base + IC_CON);
writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR);
}
if (abort & ABRT_SBYTE_ACKDET)
dev_err(&adap->dev,
"START byte was not acknowledged.\n");
if (abort & ABRT_TXDATA_NOACK)
dev_dbg(&adap->dev,
"No acknowledgement received from slave.\n");
if (abort & ABRT_10ADDR2_NOACK)
dev_dbg(&adap->dev,
"The 2nd address byte of the 10-bit address was not acknowledged.\n");
if (abort & ABRT_10ADDR1_NOACK)
dev_dbg(&adap->dev,
"The 1st address byte of 10-bit address was not acknowledged.\n");
if (abort & ABRT_7B_ADDR_NOACK)
dev_dbg(&adap->dev,
"I2C slave device not acknowledged.\n");
/* Clear TX_ABRT bit */
readl(i2c->base + IC_CLR_TX_ABRT);
i2c->status = STATUS_XFER_ABORT;
}
/**
* xfer_read - Internal function to implement master read transfer.
* @adap: i2c_adapter struct pointer
* @buf: buffer in i2c_msg
* @length: number of bytes to be read
*
* Return Values:
* 0 if the read transfer succeeds
* -ETIMEDOUT if cannot read the "raw" interrupt register
* -EINVAL if a transfer abort occurred
*
* For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to
* data transfer. The actual "read" operation will be performed if an RX_FULL
* interrupt occurred.
*
* Note there may be two interrupt signals captured, one should read
* IC_RAW_INTR_STAT to separate between errors and actual data.
*/
static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
{
struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
int i = length;
int err;
if (length >= 256) {
dev_err(&adap->dev,
"I2C FIFO cannot support larger than 256 bytes\n");
return -EMSGSIZE;
}
INIT_COMPLETION(i2c->complete);
readl(i2c->base + IC_CLR_INTR);
writel(0x0044, i2c->base + IC_INTR_MASK);
i2c->status = STATUS_READ_START;
while (i--)
writel(IC_RD, i2c->base + IC_DATA_CMD);
i2c->status = STATUS_READ_START;
err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
if (!err) {
dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
intel_mid_i2c_hwinit(i2c);
return -ETIMEDOUT;
}
if (i2c->status == STATUS_READ_SUCCESS)
return 0;
else
return -EIO;
}
/**
* xfer_write - Internal function to implement master write transfer.
* @adap: i2c_adapter struct pointer
* @buf: buffer in i2c_msg
* @length: number of bytes to be read
*
* Return Values:
* 0 if the read transfer succeeds
* -ETIMEDOUT if we cannot read the "raw" interrupt register
* -EINVAL if a transfer abort occurred
*
* For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to
* data transfer. The actual "write" operation will be performed when the
* RX_FULL interrupt signal occurs.
*
* Note there may be two interrupt signals captured, one should read
* IC_RAW_INTR_STAT to separate between errors and actual data.
*/
static int xfer_write(struct i2c_adapter *adap,
unsigned char *buf, int length)
{
struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
int i, err;
if (length >= 256) {
dev_err(&adap->dev,
"I2C FIFO cannot support larger than 256 bytes\n");
return -EMSGSIZE;
}
INIT_COMPLETION(i2c->complete);
readl(i2c->base + IC_CLR_INTR);
writel(0x0050, i2c->base + IC_INTR_MASK);
i2c->status = STATUS_WRITE_START;
for (i = 0; i < length; i++)
writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD);
i2c->status = STATUS_WRITE_START;
err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
if (!err) {
dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
intel_mid_i2c_hwinit(i2c);
return -ETIMEDOUT;
} else {
if (i2c->status == STATUS_WRITE_SUCCESS)
return 0;
else
return -EIO;
}
}
static int intel_mid_i2c_setup(struct i2c_adapter *adap, struct i2c_msg *pmsg)
{
struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
int err;
u32 reg;
u32 bit_mask;
u32 mode;
/* Disable device first */
err = intel_mid_i2c_disable(adap);
if (err) {
dev_err(&adap->dev,
"Cannot disable i2c controller, timeout\n");
return err;
}
mode = (1 + i2c->speed) << 1;
/* set the speed mode */
reg = readl(i2c->base + IC_CON);
if ((reg & 0x06) != mode) {
dev_dbg(&adap->dev, "set mode %d\n", i2c->speed);
writel((reg & ~0x6) | mode, i2c->base + IC_CON);
}
reg = readl(i2c->base + IC_CON);
/* use 7-bit addressing */
if (pmsg->flags & I2C_M_TEN) {
if ((reg & ADDR_10BIT) != ADDR_10BIT) {
dev_dbg(&adap->dev, "set i2c 10 bit address mode\n");
writel(reg | ADDR_10BIT, i2c->base + IC_CON);
}
} else {
if ((reg & ADDR_10BIT) != 0x0) {
dev_dbg(&adap->dev, "set i2c 7 bit address mode\n");
writel(reg & ~ADDR_10BIT, i2c->base + IC_CON);
}
}
/* enable restart conditions */
reg = readl(i2c->base + IC_CON);
if ((reg & RESTART) != RESTART) {
dev_dbg(&adap->dev, "enable restart conditions\n");
writel(reg | RESTART, i2c->base + IC_CON);
}
/* enable master FSM */
reg = readl(i2c->base + IC_CON);
dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
writel(reg | MASTER_EN, i2c->base + IC_CON);
if ((reg & SLV_DIS) != SLV_DIS) {
dev_dbg(&adap->dev, "enable master FSM\n");
writel(reg | SLV_DIS, i2c->base + IC_CON);
dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
}
/* use target address when initiating transfer */
reg = readl(i2c->base + IC_TAR);
bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START;
if ((reg & bit_mask) != 0x0) {
dev_dbg(&adap->dev,
"WR: use target address when intiating transfer, i2c_tx_target\n");
writel(reg & ~bit_mask, i2c->base + IC_TAR);
}
/* set target address to the I2C slave address */
dev_dbg(&adap->dev,
"set target address to the I2C slave address, addr is %x\n",
pmsg->addr);
writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0),
i2c->base + IC_TAR);
/* Enable I2C controller */
writel(ENABLE, i2c->base + IC_ENABLE);
return 0;
}
/**
* intel_mid_i2c_xfer - Main master transfer routine.
* @adap: i2c_adapter struct pointer
* @pmsg: i2c_msg struct pointer
* @num: number of i2c_msg
*
* Return Values:
* + number of messages transferred
* -ETIMEDOUT If cannot disable I2C controller or read IC_STATUS
* -EINVAL If the address in i2c_msg is invalid
*
* This function will be registered in i2c-core and exposed to external
* I2C clients.
* 1. Disable I2C controller
* 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT
* 3. Check if address in i2c_msg is valid
* 4. Enable I2C controller
* 5. Perform real transfer (call xfer_read or xfer_write)
* 6. Wait until the current transfer is finished (check bus state)
* 7. Mask and clear all interrupts
*/
static int intel_mid_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *pmsg,
int num)
{
struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
int i, err = 0;
/* if number of messages equal 0*/
if (num == 0)
return 0;
pm_runtime_get(i2c->dev);
mutex_lock(&i2c->lock);
dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num);
dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr);
if (i2c->status != STATUS_IDLE) {
dev_err(&adap->dev, "Adapter %d in transfer/standby\n",
adap->nr);
mutex_unlock(&i2c->lock);
pm_runtime_put(i2c->dev);
return -1;
}
for (i = 1; i < num; i++) {
/* Message address equal? */
if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) {
dev_err(&adap->dev, "Invalid address in msg[%d]\n", i);
mutex_unlock(&i2c->lock);
pm_runtime_put(i2c->dev);
return -EINVAL;
}
}
if (intel_mid_i2c_setup(adap, pmsg)) {
mutex_unlock(&i2c->lock);
pm_runtime_put(i2c->dev);
return -EINVAL;
}
for (i = 0; i < num; i++) {
i2c->msg = pmsg;
i2c->status = STATUS_IDLE;
/* Read or Write */
if (pmsg->flags & I2C_M_RD) {
dev_dbg(&adap->dev, "I2C_M_RD\n");
err = xfer_read(adap, pmsg->buf, pmsg->len);
} else {
dev_dbg(&adap->dev, "I2C_M_WR\n");
err = xfer_write(adap, pmsg->buf, pmsg->len);
}
if (err < 0)
break;
dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i);
pmsg++; /* next message */
}
/* Mask interrupts */
writel(0x0000, i2c->base + IC_INTR_MASK);
/* Clear all interrupts */
readl(i2c->base + IC_CLR_INTR);
i2c->status = STATUS_IDLE;
mutex_unlock(&i2c->lock);
pm_runtime_put(i2c->dev);
return err;
}
static int intel_mid_i2c_runtime_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
struct i2c_adapter *adap = to_i2c_adapter(dev);
int err;
if (i2c->status != STATUS_IDLE)
return -1;
intel_mid_i2c_disable(adap);
err = pci_save_state(pdev);
if (err) {
dev_err(dev, "pci_save_state failed\n");
return err;
}
err = pci_set_power_state(pdev, PCI_D3hot);
if (err) {
dev_err(dev, "pci_set_power_state failed\n");
return err;
}
i2c->status = STATUS_STANDBY;
return 0;
}
static int intel_mid_i2c_runtime_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
int err;
if (i2c->status != STATUS_STANDBY)
return 0;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
err = pci_enable_device(pdev);
if (err) {
dev_err(dev, "pci_enable_device failed\n");
return err;
}
i2c->status = STATUS_IDLE;
intel_mid_i2c_hwinit(i2c);
return err;
}
static void i2c_isr_read(struct intel_mid_i2c_private *i2c)
{
struct i2c_msg *msg = i2c->msg;
int rx_num;
u32 len;
u8 *buf;
if (!(msg->flags & I2C_M_RD))
return;
if (i2c->status != STATUS_READ_IN_PROGRESS) {
len = msg->len;
buf = msg->buf;
} else {
len = i2c->rx_buf_len;
buf = i2c->rx_buf;
}
rx_num = readl(i2c->base + IC_RXFLR);
for (; len > 0 && rx_num > 0; len--, rx_num--)
*buf++ = readl(i2c->base + IC_DATA_CMD);
if (len > 0) {
i2c->status = STATUS_READ_IN_PROGRESS;
i2c->rx_buf_len = len;
i2c->rx_buf = buf;
} else
i2c->status = STATUS_READ_SUCCESS;
return;
}
static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev)
{
struct intel_mid_i2c_private *i2c = dev;
u32 stat = readl(i2c->base + IC_INTR_STAT);
if (!stat)
return IRQ_NONE;
dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat);
stat &= 0x54;
if (i2c->status != STATUS_WRITE_START &&
i2c->status != STATUS_READ_START &&
i2c->status != STATUS_READ_IN_PROGRESS)
goto err;
if (stat & TX_ABRT)
i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE);
readl(i2c->base + IC_CLR_INTR);
if (stat & TX_ABRT) {
intel_mid_i2c_abort(i2c);
goto exit;
}
if (stat & RX_FULL) {
i2c_isr_read(i2c);
goto exit;
}
if (stat & TX_EMPTY) {
if (readl(i2c->base + IC_STATUS) & 0x4)
i2c->status = STATUS_WRITE_SUCCESS;
}
exit:
if (i2c->status == STATUS_READ_SUCCESS ||
i2c->status == STATUS_WRITE_SUCCESS ||
i2c->status == STATUS_XFER_ABORT) {
/* Clear all interrupts */
readl(i2c->base + IC_CLR_INTR);
/* Mask interrupts */
writel(0, i2c->base + IC_INTR_MASK);
complete(&i2c->complete);
}
err:
return IRQ_HANDLED;
}
static struct i2c_algorithm intel_mid_i2c_algorithm = {
.master_xfer = intel_mid_i2c_xfer,
.functionality = intel_mid_i2c_func,
};
static const struct dev_pm_ops intel_mid_i2c_pm_ops = {
.runtime_suspend = intel_mid_i2c_runtime_suspend,
.runtime_resume = intel_mid_i2c_runtime_resume,
};
/**
* intel_mid_i2c_probe - I2C controller initialization routine
* @dev: pci device
* @id: device id
*
* Return Values:
* 0 success
* -ENODEV If cannot allocate pci resource
* -ENOMEM If the register base remapping failed, or
* if kzalloc failed
*
* Initialization steps:
* 1. Request for PCI resource
* 2. Remap the start address of PCI resource to register base
* 3. Request for device memory region
* 4. Fill in the struct members of intel_mid_i2c_private
* 5. Call intel_mid_i2c_hwinit() for hardware initialization
* 6. Register I2C adapter in i2c-core
*/
static int intel_mid_i2c_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct intel_mid_i2c_private *mrst;
unsigned long start, len;
int err, busnum;
void __iomem *base = NULL;
dev_dbg(&dev->dev, "Get into probe function for I2C\n");
err = pci_enable_device(dev);
if (err) {
dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n",
err);
goto exit;
}
/* Determine the address of the I2C area */
start = pci_resource_start(dev, 0);
len = pci_resource_len(dev, 0);
if (!start || len == 0) {
dev_err(&dev->dev, "base address not set\n");
err = -ENODEV;
goto exit;
}
dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n",
PLATFORM, start, len);
err = pci_request_region(dev, 0, DRIVER_NAME);
if (err) {
dev_err(&dev->dev, "failed to request I2C region "
"0x%lx-0x%lx\n", start,
(unsigned long)pci_resource_end(dev, 0));
goto exit;
}
base = ioremap_nocache(start, len);
if (!base) {
dev_err(&dev->dev, "I/O memory remapping failed\n");
err = -ENOMEM;
goto fail0;
}
/* Allocate the per-device data structure, intel_mid_i2c_private */
mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL);
if (mrst == NULL) {
dev_err(&dev->dev, "can't allocate interface\n");
err = -ENOMEM;
goto fail1;
}
/* Initialize struct members */
snprintf(mrst->adap.name, sizeof(mrst->adap.name),
"Intel MID I2C at %lx", start);
mrst->adap.owner = THIS_MODULE;
mrst->adap.algo = &intel_mid_i2c_algorithm;
mrst->adap.dev.parent = &dev->dev;
mrst->dev = &dev->dev;
mrst->base = base;
mrst->speed = STANDARD;
mrst->abort = 0;
mrst->rx_buf_len = 0;
mrst->status = STATUS_IDLE;
pci_set_drvdata(dev, mrst);
i2c_set_adapdata(&mrst->adap, mrst);
mrst->adap.nr = busnum = id->driver_data;
if (dev->device <= 0x0804)
mrst->platform = MOORESTOWN;
else
mrst->platform = MEDFIELD;
dev_dbg(&dev->dev, "I2C%d\n", busnum);
if (ctl_num > busnum) {
if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS)
dev_warn(&dev->dev, "invalid speed %d ignored.\n",
speed_mode[busnum]);
else
mrst->speed = speed_mode[busnum];
}
/* Initialize i2c controller */
err = intel_mid_i2c_hwinit(mrst);
if (err < 0) {
dev_err(&dev->dev, "I2C interface initialization failed\n");
goto fail2;
}
mutex_init(&mrst->lock);
init_completion(&mrst->complete);
/* Clear all interrupts */
readl(mrst->base + IC_CLR_INTR);
writel(0x0000, mrst->base + IC_INTR_MASK);
err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED,
mrst->adap.name, mrst);
if (err) {
dev_err(&dev->dev, "Failed to request IRQ for I2C controller: "
"%s", mrst->adap.name);
goto fail2;
}
/* Adapter registration */
err = i2c_add_numbered_adapter(&mrst->adap);
if (err) {
dev_err(&dev->dev, "Adapter %s registration failed\n",
mrst->adap.name);
goto fail3;
}
dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n",
(mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield",
busnum);
pm_runtime_enable(&dev->dev);
return 0;
fail3:
free_irq(dev->irq, mrst);
fail2:
kfree(mrst);
fail1:
iounmap(base);
fail0:
pci_release_region(dev, 0);
exit:
return err;
}
static void intel_mid_i2c_remove(struct pci_dev *dev)
{
struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev);
intel_mid_i2c_disable(&mrst->adap);
i2c_del_adapter(&mrst->adap);
free_irq(dev->irq, mrst);
iounmap(mrst->base);
kfree(mrst);
pci_release_region(dev, 0);
}
static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = {
/* Moorestown */
{ PCI_VDEVICE(INTEL, 0x0802), 0 },
{ PCI_VDEVICE(INTEL, 0x0803), 1 },
{ PCI_VDEVICE(INTEL, 0x0804), 2 },
/* Medfield */
{ PCI_VDEVICE(INTEL, 0x0817), 3,},
{ PCI_VDEVICE(INTEL, 0x0818), 4 },
{ PCI_VDEVICE(INTEL, 0x0819), 5 },
{ PCI_VDEVICE(INTEL, 0x082C), 0 },
{ PCI_VDEVICE(INTEL, 0x082D), 1 },
{ PCI_VDEVICE(INTEL, 0x082E), 2 },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids);
static struct pci_driver intel_mid_i2c_driver = {
.name = DRIVER_NAME,
.id_table = intel_mid_i2c_ids,
.probe = intel_mid_i2c_probe,
.remove = intel_mid_i2c_remove,
};
module_pci_driver(intel_mid_i2c_driver);
MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
MODULE_LICENSE("GPL");
MODULE_VERSION(VERSION);
......@@ -176,7 +176,7 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
interrupted = wait_event_interruptible_timeout (
iop3xx_adap->waitq,
(done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )),
1 * HZ;
1 * HZ
);
if ((rc = iop3xx_i2c_error(sr)) < 0) {
*status = sr;
......
/*
* I2C bus driver for Kontron COM modules
*
* Copyright (c) 2010-2013 Kontron Europe GmbH
* Author: Michael Brunner <michael.brunner@kontron.com>
*
* The driver is based on the i2c-ocores driver by Peter Korsgaard.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 2 as published
* by the Free Software Foundation.
*
* 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/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/mfd/kempld.h>
#define KEMPLD_I2C_PRELOW 0x0b
#define KEMPLD_I2C_PREHIGH 0x0c
#define KEMPLD_I2C_DATA 0x0e
#define KEMPLD_I2C_CTRL 0x0d
#define I2C_CTRL_IEN 0x40
#define I2C_CTRL_EN 0x80
#define KEMPLD_I2C_STAT 0x0f
#define I2C_STAT_IF 0x01
#define I2C_STAT_TIP 0x02
#define I2C_STAT_ARBLOST 0x20
#define I2C_STAT_BUSY 0x40
#define I2C_STAT_NACK 0x80
#define KEMPLD_I2C_CMD 0x0f
#define I2C_CMD_START 0x91
#define I2C_CMD_STOP 0x41
#define I2C_CMD_READ 0x21
#define I2C_CMD_WRITE 0x11
#define I2C_CMD_READ_ACK 0x21
#define I2C_CMD_READ_NACK 0x29
#define I2C_CMD_IACK 0x01
#define KEMPLD_I2C_FREQ_MAX 2700 /* 2.7 mHz */
#define KEMPLD_I2C_FREQ_STD 100 /* 100 kHz */
enum {
STATE_DONE = 0,
STATE_INIT,
STATE_ADDR,
STATE_ADDR10,
STATE_START,
STATE_WRITE,
STATE_READ,
STATE_ERROR,
};
struct kempld_i2c_data {
struct device *dev;
struct kempld_device_data *pld;
struct i2c_adapter adap;
struct i2c_msg *msg;
int pos;
int nmsgs;
int state;
bool was_active;
};
static unsigned int bus_frequency = KEMPLD_I2C_FREQ_STD;
module_param(bus_frequency, uint, 0);
MODULE_PARM_DESC(bus_frequency, "Set I2C bus frequency in kHz (default="
__MODULE_STRING(KEMPLD_I2C_FREQ_STD)")");
static int i2c_bus = -1;
module_param(i2c_bus, int, 0);
MODULE_PARM_DESC(i2c_bus, "Set I2C bus number (default=-1 for dynamic assignment)");
static bool i2c_gpio_mux;
module_param(i2c_gpio_mux, bool, 0);
MODULE_PARM_DESC(i2c_gpio_mux, "Enable I2C port on GPIO out (default=false)");
/*
* kempld_get_mutex must be called prior to calling this function.
*/
static int kempld_i2c_process(struct kempld_i2c_data *i2c)
{
struct kempld_device_data *pld = i2c->pld;
u8 stat = kempld_read8(pld, KEMPLD_I2C_STAT);
struct i2c_msg *msg = i2c->msg;
u8 addr;
/* Ready? */
if (stat & I2C_STAT_TIP)
return -EBUSY;
if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
/* Stop has been sent */
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
if (i2c->state == STATE_ERROR)
return -EIO;
return 0;
}
/* Error? */
if (stat & I2C_STAT_ARBLOST) {
i2c->state = STATE_ERROR;
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
return -EAGAIN;
}
if (i2c->state == STATE_INIT) {
if (stat & I2C_STAT_BUSY)
return -EBUSY;
i2c->state = STATE_ADDR;
}
if (i2c->state == STATE_ADDR) {
/* 10 bit address? */
if (i2c->msg->flags & I2C_M_TEN) {
addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6);
i2c->state = STATE_ADDR10;
} else {
addr = (i2c->msg->addr << 1);
i2c->state = STATE_START;
}
/* Set read bit if necessary */
addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
kempld_write8(pld, KEMPLD_I2C_DATA, addr);
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START);
return 0;
}
/* Second part of 10 bit addressing */
if (i2c->state == STATE_ADDR10) {
kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff);
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
i2c->state = STATE_START;
return 0;
}
if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
if (stat & I2C_STAT_NACK) {
i2c->state = STATE_ERROR;
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
return -ENXIO;
}
} else {
msg->buf[i2c->pos++] = kempld_read8(pld, KEMPLD_I2C_DATA);
}
if (i2c->pos >= msg->len) {
i2c->nmsgs--;
i2c->msg++;
i2c->pos = 0;
msg = i2c->msg;
if (i2c->nmsgs) {
if (!(msg->flags & I2C_M_NOSTART)) {
i2c->state = STATE_ADDR;
return 0;
} else {
i2c->state = (msg->flags & I2C_M_RD)
? STATE_READ : STATE_WRITE;
}
} else {
i2c->state = STATE_DONE;
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
return 0;
}
}
if (i2c->state == STATE_READ) {
kempld_write8(pld, KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ?
I2C_CMD_READ_NACK : I2C_CMD_READ_ACK);
} else {
kempld_write8(pld, KEMPLD_I2C_DATA, msg->buf[i2c->pos++]);
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
}
return 0;
}
static int kempld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct kempld_i2c_data *i2c = i2c_get_adapdata(adap);
struct kempld_device_data *pld = i2c->pld;
unsigned long timeout = jiffies + HZ;
int ret;
i2c->msg = msgs;
i2c->pos = 0;
i2c->nmsgs = num;
i2c->state = STATE_INIT;
/* Handle the transfer */
while (time_before(jiffies, timeout)) {
kempld_get_mutex(pld);
ret = kempld_i2c_process(i2c);
kempld_release_mutex(pld);
if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR)
return (i2c->state == STATE_DONE) ? num : ret;
if (ret == 0)
timeout = jiffies + HZ;
usleep_range(5, 15);
}
i2c->state = STATE_ERROR;
return -ETIMEDOUT;
}
/*
* kempld_get_mutex must be called prior to calling this function.
*/
static void kempld_i2c_device_init(struct kempld_i2c_data *i2c)
{
struct kempld_device_data *pld = i2c->pld;
u16 prescale_corr;
long prescale;
u8 ctrl;
u8 stat;
u8 cfg;
/* Make sure the device is disabled */
ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
if (bus_frequency > KEMPLD_I2C_FREQ_MAX)
bus_frequency = KEMPLD_I2C_FREQ_MAX;
if (pld->info.spec_major == 1)
prescale = pld->pld_clock / bus_frequency * 5 - 1000;
else
prescale = pld->pld_clock / bus_frequency * 4 - 3000;
if (prescale < 0)
prescale = 0;
/* Round to the best matching value */
prescale_corr = prescale / 1000;
if (prescale % 1000 >= 500)
prescale_corr++;
kempld_write8(pld, KEMPLD_I2C_PRELOW, prescale_corr & 0xff);
kempld_write8(pld, KEMPLD_I2C_PREHIGH, prescale_corr >> 8);
/* Activate I2C bus output on GPIO pins */
cfg = kempld_read8(pld, KEMPLD_CFG);
if (i2c_gpio_mux)
cfg |= KEMPLD_CFG_GPIO_I2C_MUX;
else
cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX;
kempld_write8(pld, KEMPLD_CFG, cfg);
/* Enable the device */
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
ctrl |= I2C_CTRL_EN;
kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
stat = kempld_read8(pld, KEMPLD_I2C_STAT);
if (stat & I2C_STAT_BUSY)
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
}
static u32 kempld_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm kempld_i2c_algorithm = {
.master_xfer = kempld_i2c_xfer,
.functionality = kempld_i2c_func,
};
static struct i2c_adapter kempld_i2c_adapter = {
.owner = THIS_MODULE,
.name = "i2c-kempld",
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
.algo = &kempld_i2c_algorithm,
};
static int kempld_i2c_probe(struct platform_device *pdev)
{
struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
struct kempld_i2c_data *i2c;
int ret;
u8 ctrl;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
i2c->pld = pld;
i2c->dev = &pdev->dev;
i2c->adap = kempld_i2c_adapter;
i2c->adap.dev.parent = i2c->dev;
i2c_set_adapdata(&i2c->adap, i2c);
platform_set_drvdata(pdev, i2c);
kempld_get_mutex(pld);
ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
if (ctrl & I2C_CTRL_EN)
i2c->was_active = true;
kempld_i2c_device_init(i2c);
kempld_release_mutex(pld);
/* Add I2C adapter to I2C tree */
if (i2c_bus >= -1)
i2c->adap.nr = i2c_bus;
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret)
return ret;
dev_info(i2c->dev, "I2C bus initialized at %dkHz\n",
bus_frequency);
return 0;
}
static int kempld_i2c_remove(struct platform_device *pdev)
{
struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
struct kempld_device_data *pld = i2c->pld;
u8 ctrl;
kempld_get_mutex(pld);
/*
* Disable I2C logic if it was not activated before the
* driver loaded
*/
if (!i2c->was_active) {
ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
ctrl &= ~I2C_CTRL_EN;
kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
}
kempld_release_mutex(pld);
i2c_del_adapter(&i2c->adap);
return 0;
}
#ifdef CONFIG_PM
static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state)
{
struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
struct kempld_device_data *pld = i2c->pld;
u8 ctrl;
kempld_get_mutex(pld);
ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
ctrl &= ~I2C_CTRL_EN;
kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
kempld_release_mutex(pld);
return 0;
}
static int kempld_i2c_resume(struct platform_device *pdev)
{
struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
struct kempld_device_data *pld = i2c->pld;
kempld_get_mutex(pld);
kempld_i2c_device_init(i2c);
kempld_release_mutex(pld);
return 0;
}
#else
#define kempld_i2c_suspend NULL
#define kempld_i2c_resume NULL
#endif
static struct platform_driver kempld_i2c_driver = {
.driver = {
.name = "kempld-i2c",
.owner = THIS_MODULE,
},
.probe = kempld_i2c_probe,
.remove = kempld_i2c_remove,
.suspend = kempld_i2c_suspend,
.resume = kempld_i2c_resume,
};
module_platform_driver(kempld_i2c_driver);
MODULE_DESCRIPTION("KEM PLD I2C Driver");
MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:kempld_i2c");
......@@ -679,7 +679,7 @@ static int fsl_i2c_probe(struct platform_device *op)
}
dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
dev_set_drvdata(&op->dev, i2c);
platform_set_drvdata(op, i2c);
i2c->adap = mpc_ops;
i2c_set_adapdata(&i2c->adap, i2c);
......@@ -707,7 +707,7 @@ static int fsl_i2c_probe(struct platform_device *op)
static int fsl_i2c_remove(struct platform_device *op)
{
struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
struct mpc_i2c *i2c = platform_get_drvdata(op);
i2c_del_adapter(&i2c->adap);
......
......@@ -19,19 +19,15 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_i2c.h>
#include <linux/clk.h>
#include <linux/err.h>
/* Register defines */
#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00
#define MV64XXX_I2C_REG_DATA 0x04
#define MV64XXX_I2C_REG_CONTROL 0x08
#define MV64XXX_I2C_REG_STATUS 0x0c
#define MV64XXX_I2C_REG_BAUD 0x0c
#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10
#define MV64XXX_I2C_REG_SOFT_RESET 0x1c
#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1)
#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3)
#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004
#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008
......@@ -85,15 +81,26 @@ enum {
MV64XXX_I2C_ACTION_SEND_STOP,
};
struct mv64xxx_i2c_regs {
u8 addr;
u8 ext_addr;
u8 data;
u8 control;
u8 status;
u8 clock;
u8 soft_reset;
};
struct mv64xxx_i2c_data {
struct i2c_msg *msgs;
int num_msgs;
int irq;
u32 state;
u32 action;
u32 aborting;
u32 cntl_bits;
void __iomem *reg_base;
u32 reg_base_p;
u32 reg_size;
struct mv64xxx_i2c_regs reg_offsets;
u32 addr1;
u32 addr2;
u32 bytes_left;
......@@ -112,6 +119,52 @@ struct mv64xxx_i2c_data {
struct i2c_adapter adapter;
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
.addr = 0x00,
.ext_addr = 0x10,
.data = 0x04,
.control = 0x08,
.status = 0x0c,
.clock = 0x0c,
.soft_reset = 0x1c,
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_sun4i = {
.addr = 0x00,
.ext_addr = 0x04,
.data = 0x08,
.control = 0x0c,
.status = 0x10,
.clock = 0x14,
.soft_reset = 0x18,
};
static void
mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
struct i2c_msg *msg)
{
u32 dir = 0;
drv_data->msg = msg;
drv_data->byte_posn = 0;
drv_data->bytes_left = msg->len;
drv_data->aborting = 0;
drv_data->rc = 0;
drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
if (msg->flags & I2C_M_RD)
dir = 1;
if (msg->flags & I2C_M_TEN) {
drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
drv_data->addr2 = (u32)msg->addr & 0xff;
} else {
drv_data->addr1 = MV64XXX_I2C_ADDR_ADDR((u32)msg->addr) | dir;
drv_data->addr2 = 0;
}
}
/*
*****************************************************************************
*
......@@ -124,13 +177,13 @@ struct mv64xxx_i2c_data {
static void
mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
{
writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
writel(0, drv_data->reg_base + drv_data->reg_offsets.soft_reset);
writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n),
drv_data->reg_base + drv_data->reg_offsets.clock);
writel(0, drv_data->reg_base + drv_data->reg_offsets.addr);
writel(0, drv_data->reg_base + drv_data->reg_offsets.ext_addr);
writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->state = MV64XXX_I2C_STATE_IDLE;
}
......@@ -170,7 +223,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
if ((drv_data->bytes_left == 0)
|| (drv_data->aborting
&& (drv_data->byte_posn != 0))) {
if (drv_data->send_stop) {
if (drv_data->send_stop || drv_data->aborting) {
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
drv_data->state = MV64XXX_I2C_STATE_IDLE;
} else {
......@@ -227,7 +280,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
/* Doesn't seem to be a device at other end */
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
drv_data->state = MV64XXX_I2C_STATE_IDLE;
drv_data->rc = -ENODEV;
drv_data->rc = -ENXIO;
break;
default:
......@@ -247,58 +300,71 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{
switch(drv_data->action) {
case MV64XXX_I2C_ACTION_SEND_RESTART:
/* We should only get here if we have further messages */
BUG_ON(drv_data->num_msgs == 0);
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->block = 0;
wake_up(&drv_data->waitq);
drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->msgs++;
drv_data->num_msgs--;
/* Setup for the next message */
mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
/*
* We're never at the start of the message here, and by this
* time it's already too late to do any protocol mangling.
* Thankfully, do not advertise support for that feature.
*/
drv_data->send_stop = drv_data->num_msgs == 1;
break;
case MV64XXX_I2C_ACTION_CONTINUE:
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_START:
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_ADDR_1:
writel(drv_data->addr1,
drv_data->reg_base + MV64XXX_I2C_REG_DATA);
drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_ADDR_2:
writel(drv_data->addr2,
drv_data->reg_base + MV64XXX_I2C_REG_DATA);
drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_DATA:
writel(drv_data->msg->buf[drv_data->byte_posn++],
drv_data->reg_base + MV64XXX_I2C_REG_DATA);
drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_RCV_DATA:
drv_data->msg->buf[drv_data->byte_posn++] =
readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
readl(drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
drv_data->msg->buf[drv_data->byte_posn++] =
readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
readl(drv_data->reg_base + drv_data->reg_offsets.data);
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->block = 0;
wake_up(&drv_data->waitq);
break;
......@@ -313,7 +379,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
case MV64XXX_I2C_ACTION_SEND_STOP:
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->block = 0;
wake_up(&drv_data->waitq);
break;
......@@ -329,9 +395,9 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
irqreturn_t rc = IRQ_NONE;
spin_lock_irqsave(&drv_data->lock, flags);
while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
MV64XXX_I2C_REG_CONTROL_IFLG) {
status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
mv64xxx_i2c_fsm(drv_data, status);
mv64xxx_i2c_do_action(drv_data);
rc = IRQ_HANDLED;
......@@ -348,32 +414,6 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
*
*****************************************************************************
*/
static void
mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
struct i2c_msg *msg)
{
u32 dir = 0;
drv_data->msg = msg;
drv_data->byte_posn = 0;
drv_data->bytes_left = msg->len;
drv_data->aborting = 0;
drv_data->rc = 0;
drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
if (msg->flags & I2C_M_RD)
dir = 1;
if (msg->flags & I2C_M_TEN) {
drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
drv_data->addr2 = (u32)msg->addr & 0xff;
} else {
drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir;
drv_data->addr2 = 0;
}
}
static void
mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
{
......@@ -414,36 +454,15 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
static int
mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
int is_first, int is_last)
int is_last)
{
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
mv64xxx_i2c_prepare_for_io(drv_data, msg);
if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */
if (drv_data->msg->flags & I2C_M_RD) {
/* No action to do, wait for slave to send a byte */
drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
drv_data->state =
MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
} else {
drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
drv_data->state =
MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
drv_data->bytes_left--;
}
} else {
if (is_first) {
drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
drv_data->state =
MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
} else {
drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
drv_data->state =
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
}
}
drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
drv_data->send_stop = is_last;
drv_data->block = 1;
......@@ -471,16 +490,20 @@ static int
mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
int i, rc;
int rc, ret = num;
for (i = 0; i < num; i++) {
rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i],
i == 0, i + 1 == num);
if (rc < 0)
return rc;
}
BUG_ON(drv_data->msgs != NULL);
drv_data->msgs = msgs;
drv_data->num_msgs = num;
rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1);
if (rc < 0)
ret = rc;
drv_data->num_msgs = 0;
drv_data->msgs = NULL;
return num;
return ret;
}
static const struct i2c_algorithm mv64xxx_i2c_algo = {
......@@ -495,39 +518,12 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
*
*****************************************************************************
*/
static int
mv64xxx_i2c_map_regs(struct platform_device *pd,
struct mv64xxx_i2c_data *drv_data)
{
int size;
struct resource *r = platform_get_resource(pd, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
size = resource_size(r);
if (!request_mem_region(r->start, size, drv_data->adapter.name))
return -EBUSY;
drv_data->reg_base = ioremap(r->start, size);
drv_data->reg_base_p = r->start;
drv_data->reg_size = size;
return 0;
}
static void
mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
{
if (drv_data->reg_base) {
iounmap(drv_data->reg_base);
release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
}
drv_data->reg_base = NULL;
drv_data->reg_base_p = 0;
}
static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
{ .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
{ .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{}
};
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
#ifdef CONFIG_OF
static int
......@@ -562,8 +558,10 @@ mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
static int
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
struct device_node *np)
struct device *dev)
{
const struct of_device_id *device;
struct device_node *np = dev->of_node;
u32 bus_freq, tclk;
int rc = 0;
......@@ -580,7 +578,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
goto out;
}
tclk = clk_get_rate(drv_data->clk);
of_property_read_u32(np, "clock-frequency", &bus_freq);
rc = of_property_read_u32(np, "clock-frequency", &bus_freq);
if (rc)
bus_freq = 100000; /* 100kHz by default */
if (!mv64xxx_find_baud_factors(bus_freq, tclk,
&drv_data->freq_n, &drv_data->freq_m)) {
rc = -EINVAL;
......@@ -592,6 +594,13 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
* So hard code the value to 1 second.
*/
drv_data->adapter.timeout = HZ;
device = of_match_device(mv64xxx_i2c_of_match_table, dev);
if (!device)
return -ENODEV;
memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets));
out:
return rc;
#endif
......@@ -599,7 +608,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
#else /* CONFIG_OF */
static int
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
struct device_node *np)
struct device *dev)
{
return -ENODEV;
}
......@@ -610,19 +619,21 @@ mv64xxx_i2c_probe(struct platform_device *pd)
{
struct mv64xxx_i2c_data *drv_data;
struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data;
struct resource *r;
int rc;
if ((!pdata && !pd->dev.of_node))
return -ENODEV;
drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
drv_data = devm_kzalloc(&pd->dev, sizeof(struct mv64xxx_i2c_data),
GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
if (mv64xxx_i2c_map_regs(pd, drv_data)) {
rc = -ENODEV;
goto exit_kfree;
}
r = platform_get_resource(pd, IORESOURCE_MEM, 0);
drv_data->reg_base = devm_ioremap_resource(&pd->dev, r);
if (IS_ERR(drv_data->reg_base))
return PTR_ERR(drv_data->reg_base);
strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
sizeof(drv_data->adapter.name));
......@@ -632,7 +643,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
drv_data->clk = clk_get(&pd->dev, NULL);
drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (!IS_ERR(drv_data->clk)) {
clk_prepare(drv_data->clk);
clk_enable(drv_data->clk);
......@@ -643,14 +654,15 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->freq_n = pdata->freq_n;
drv_data->irq = platform_get_irq(pd, 0);
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
memcpy(&drv_data->reg_offsets, &mv64xxx_i2c_regs_mv64xxx, sizeof(drv_data->reg_offsets));
} else if (pd->dev.of_node) {
rc = mv64xxx_of_config(drv_data, pd->dev.of_node);
rc = mv64xxx_of_config(drv_data, &pd->dev);
if (rc)
goto exit_unmap_regs;
goto exit_clk;
}
if (drv_data->irq < 0) {
rc = -ENXIO;
goto exit_unmap_regs;
goto exit_clk;
}
drv_data->adapter.dev.parent = &pd->dev;
......@@ -664,13 +676,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
mv64xxx_i2c_hw_init(drv_data);
if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
MV64XXX_I2C_CTLR_NAME, drv_data)) {
rc = request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
MV64XXX_I2C_CTLR_NAME, drv_data);
if (rc) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't register intr handler irq: %d\n",
drv_data->irq);
rc = -EINVAL;
goto exit_unmap_regs;
"mv64xxx: Can't register intr handler irq%d: %d\n",
drv_data->irq, rc);
goto exit_clk;
} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
......@@ -681,9 +693,9 @@ mv64xxx_i2c_probe(struct platform_device *pd)
return 0;
exit_free_irq:
free_irq(drv_data->irq, drv_data);
exit_unmap_regs:
exit_free_irq:
free_irq(drv_data->irq, drv_data);
exit_clk:
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) {
......@@ -691,9 +703,6 @@ mv64xxx_i2c_probe(struct platform_device *pd)
clk_unprepare(drv_data->clk);
}
#endif
mv64xxx_i2c_unmap_regs(drv_data);
exit_kfree:
kfree(drv_data);
return rc;
}
......@@ -704,7 +713,6 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
mv64xxx_i2c_unmap_regs(drv_data);
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) {
......@@ -712,17 +720,10 @@ mv64xxx_i2c_remove(struct platform_device *dev)
clk_unprepare(drv_data->clk);
}
#endif
kfree(drv_data);
return 0;
}
static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
{ .compatible = "marvell,mv64xxx-i2c", },
{}
};
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
static struct platform_driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe,
.remove = mv64xxx_i2c_remove,
......
......@@ -24,7 +24,6 @@
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/pinctrl/consumer.h>
#include <linux/stmp_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
......@@ -638,15 +637,10 @@ static int mxs_i2c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap;
struct pinctrl *pinctrl;
struct resource *res;
resource_size_t res_size;
int err, irq;
pinctrl = devm_pinctrl_get_select_default(dev);
if (IS_ERR(pinctrl))
return PTR_ERR(pinctrl);
i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
......
......@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/amba/bus.h>
#include <linux/atomic.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
......@@ -106,6 +105,16 @@
/* maximum threshold value */
#define MAX_I2C_FIFO_THRESHOLD 15
/**
* struct i2c_vendor_data - per-vendor variations
* @has_mtdws: variant has the MTDWS bit
* @fifodepth: variant FIFO depth
*/
struct i2c_vendor_data {
bool has_mtdws;
u32 fifodepth;
};
enum i2c_status {
I2C_NOP,
I2C_ON_GOING,
......@@ -138,6 +147,7 @@ struct i2c_nmk_client {
/**
* struct nmk_i2c_dev - private data structure of the controller.
* @vendor: vendor data for this variant.
* @adev: parent amba device.
* @adap: corresponding I2C adapter.
* @irq: interrupt line for the controller.
......@@ -151,6 +161,7 @@ struct i2c_nmk_client {
* @busy: Busy doing transfer.
*/
struct nmk_i2c_dev {
struct i2c_vendor_data *vendor;
struct amba_device *adev;
struct i2c_adapter adap;
int irq;
......@@ -422,7 +433,7 @@ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
I2C_IT_MAL | I2C_IT_BERR);
if (dev->stop)
if (dev->stop || !dev->vendor->has_mtdws)
irq_mask |= I2C_IT_MTD;
else
irq_mask |= I2C_IT_MTDWS;
......@@ -502,7 +513,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
* set the MTDWS bit (Master Transaction Done Without Stop)
* to start repeated start operation
*/
if (dev->stop)
if (dev->stop || !dev->vendor->has_mtdws)
irq_mask |= I2C_IT_MTD;
else
irq_mask |= I2C_IT_MTDWS;
......@@ -929,8 +940,6 @@ static void nmk_i2c_of_probe(struct device_node *np,
pdata->sm = I2C_FREQ_MODE_FAST;
}
static atomic_t adapter_id = ATOMIC_INIT(0);
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
......@@ -938,6 +947,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
struct device_node *np = adev->dev.of_node;
struct nmk_i2c_dev *dev;
struct i2c_adapter *adap;
struct i2c_vendor_data *vendor = id->data;
u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
if (!pdata) {
if (np) {
......@@ -954,12 +965,25 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
pdata = &u8500_i2c;
}
if (pdata->tft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
pdata->tft, max_fifo_threshold);
pdata->tft = max_fifo_threshold;
}
if (pdata->rft > max_fifo_threshold) {
dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
pdata->rft, max_fifo_threshold);
pdata->rft = max_fifo_threshold;
}
dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
if (!dev) {
dev_err(&adev->dev, "cannot allocate memory\n");
ret = -ENOMEM;
goto err_no_mem;
}
dev->vendor = vendor;
dev->busy = false;
dev->adev = adev;
amba_set_drvdata(adev, dev);
......@@ -999,10 +1023,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->algo = &nmk_i2c_algo;
adap->timeout = msecs_to_jiffies(pdata->timeout);
adap->nr = atomic_read(&adapter_id);
snprintf(adap->name, sizeof(adap->name),
"Nomadik I2C%d at %pR", adap->nr, &adev->res);
atomic_inc(&adapter_id);
"Nomadik I2C at %pR", &adev->res);
/* fetch the controller configuration from machine */
dev->cfg.clk_freq = pdata->clk_freq;
......@@ -1017,7 +1039,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
"initialize %s on virtual base %p\n",
adap->name, dev->virtbase);
ret = i2c_add_numbered_adapter(adap);
ret = i2c_add_adapter(adap);
if (ret) {
dev_err(&adev->dev, "failed to add adapter\n");
goto err_add_adap;
......@@ -1064,14 +1086,26 @@ static int nmk_i2c_remove(struct amba_device *adev)
return 0;
}
static struct i2c_vendor_data vendor_stn8815 = {
.has_mtdws = false,
.fifodepth = 16, /* Guessed from TFTR/RFTR = 7 */
};
static struct i2c_vendor_data vendor_db8500 = {
.has_mtdws = true,
.fifodepth = 32, /* Guessed from TFTR/RFTR = 15 */
};
static struct amba_id nmk_i2c_ids[] = {
{
.id = 0x00180024,
.mask = 0x00ffffff,
.data = &vendor_stn8815,
},
{
.id = 0x00380024,
.mask = 0x00ffffff,
.data = &vendor_db8500,
},
{},
};
......
......@@ -180,6 +180,8 @@ enum {
#define I2C_OMAP_ERRATA_I207 (1 << 0)
#define I2C_OMAP_ERRATA_I462 (1 << 1)
#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF
struct omap_i2c_dev {
spinlock_t lock; /* IRQ synchronization */
struct device *dev;
......@@ -193,6 +195,7 @@ struct omap_i2c_dev {
long latency);
u32 speed; /* Speed of bus in kHz */
u32 flags;
u16 scheme;
u16 cmd_err;
u8 *buf;
u8 *regs;
......@@ -1082,14 +1085,7 @@ omap_i2c_probe(struct platform_device *pdev)
int irq;
int r;
u32 rev;
u16 minor, major, scheme;
/* NOTE: driver uses the static register mapping */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "no mem resource?\n");
return -ENODEV;
}
u16 minor, major;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
......@@ -1103,6 +1099,7 @@ omap_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
......@@ -1159,8 +1156,8 @@ omap_i2c_probe(struct platform_device *pdev)
*/
rev = __raw_readw(dev->base + 0x04);
scheme = OMAP_I2C_SCHEME(rev);
switch (scheme) {
dev->scheme = OMAP_I2C_SCHEME(rev);
switch (dev->scheme) {
case OMAP_I2C_SCHEME_0:
dev->regs = (u8 *)reg_map_ip_v1;
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG);
......@@ -1289,7 +1286,11 @@ static int omap_i2c_runtime_suspend(struct device *dev)
_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
if (_dev->scheme == OMAP_I2C_SCHEME_0)
omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
else
omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR,
OMAP_I2C_IP_V2_INTERRUPTS_MASK);
if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
......
......@@ -1160,7 +1160,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.class = plat->class;
}
clk_enable(i2c->clk);
clk_prepare_enable(i2c->clk);
if (i2c->use_pio) {
i2c->adap.algo = &i2c_pxa_pio_algorithm;
......@@ -1202,7 +1202,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
if (!i2c->use_pio)
free_irq(irq, i2c);
ereqirq:
clk_disable(i2c->clk);
clk_disable_unprepare(i2c->clk);
iounmap(i2c->reg_base);
eremap:
clk_put(i2c->clk);
......@@ -1221,7 +1221,7 @@ static int i2c_pxa_remove(struct platform_device *dev)
if (!i2c->use_pio)
free_irq(i2c->irq, i2c);
clk_disable(i2c->clk);
clk_disable_unprepare(i2c->clk);
clk_put(i2c->clk);
iounmap(i2c->reg_base);
......
......@@ -623,12 +623,6 @@ static int rcar_i2c_probe(struct platform_device *pdev)
u32 bus_speed;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "no mmio resources\n");
return -ENODEV;
}
priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
if (!priv) {
dev_err(dev, "no mem for private data\n");
......@@ -642,6 +636,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->io))
return PTR_ERR(priv->io);
......
/*
* Wondermedia I2C Master Mode Driver
*
* Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
*
* Derived from GPLv2+ licensed source:
* - Copyright (C) 2008 WonderMedia Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, or
* (at your option) any later version. as published by the Free Software
* Foundation
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_i2c.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#define REG_CR 0x00
#define REG_TCR 0x02
#define REG_CSR 0x04
#define REG_ISR 0x06
#define REG_IMR 0x08
#define REG_CDR 0x0A
#define REG_TR 0x0C
#define REG_MCR 0x0E
#define REG_SLAVE_CR 0x10
#define REG_SLAVE_SR 0x12
#define REG_SLAVE_ISR 0x14
#define REG_SLAVE_IMR 0x16
#define REG_SLAVE_DR 0x18
#define REG_SLAVE_TR 0x1A
/* REG_CR Bit fields */
#define CR_TX_NEXT_ACK 0x0000
#define CR_ENABLE 0x0001
#define CR_TX_NEXT_NO_ACK 0x0002
#define CR_TX_END 0x0004
#define CR_CPU_RDY 0x0008
#define SLAV_MODE_SEL 0x8000
/* REG_TCR Bit fields */
#define TCR_STANDARD_MODE 0x0000
#define TCR_MASTER_WRITE 0x0000
#define TCR_HS_MODE 0x2000
#define TCR_MASTER_READ 0x4000
#define TCR_FAST_MODE 0x8000
#define TCR_SLAVE_ADDR_MASK 0x007F
/* REG_ISR Bit fields */
#define ISR_NACK_ADDR 0x0001
#define ISR_BYTE_END 0x0002
#define ISR_SCL_TIMEOUT 0x0004
#define ISR_WRITE_ALL 0x0007
/* REG_IMR Bit fields */
#define IMR_ENABLE_ALL 0x0007
/* REG_CSR Bit fields */
#define CSR_RCV_NOT_ACK 0x0001
#define CSR_RCV_ACK_MASK 0x0001
#define CSR_READY_MASK 0x0002
/* REG_TR */
#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8)
#define TR_STD 0x0064
#define TR_HS 0x0019
/* REG_MCR */
#define MCR_APB_96M 7
#define MCR_APB_166M 12
#define I2C_MODE_STANDARD 0
#define I2C_MODE_FAST 1
#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000))
struct wmt_i2c_dev {
struct i2c_adapter adapter;
struct completion complete;
struct device *dev;
void __iomem *base;
struct clk *clk;
int mode;
int irq;
u16 cmd_status;
};
static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
{
unsigned long timeout;
timeout = jiffies + WMT_I2C_TIMEOUT;
while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
if (time_after(jiffies, timeout)) {
dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
return -EBUSY;
}
msleep(20);
}
return 0;
}
static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
{
int ret = 0;
if (i2c_dev->cmd_status & ISR_NACK_ADDR)
ret = -EIO;
if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
ret = -ETIMEDOUT;
return ret;
}
static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
int last)
{
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
u16 val, tcr_val;
int ret, wait_result;
int xfer_len = 0;
if (!(pmsg->flags & I2C_M_NOSTART)) {
ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
if (ret < 0)
return ret;
}
if (pmsg->len == 0) {
/*
* We still need to run through the while (..) once, so
* start at -1 and break out early from the loop
*/
xfer_len = -1;
writew(0, i2c_dev->base + REG_CDR);
} else {
writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
}
if (!(pmsg->flags & I2C_M_NOSTART)) {
val = readw(i2c_dev->base + REG_CR);
val &= ~CR_TX_END;
writew(val, i2c_dev->base + REG_CR);
val = readw(i2c_dev->base + REG_CR);
val |= CR_CPU_RDY;
writew(val, i2c_dev->base + REG_CR);
}
INIT_COMPLETION(i2c_dev->complete);
if (i2c_dev->mode == I2C_MODE_STANDARD)
tcr_val = TCR_STANDARD_MODE;
else
tcr_val = TCR_FAST_MODE;
tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
writew(tcr_val, i2c_dev->base + REG_TCR);
if (pmsg->flags & I2C_M_NOSTART) {
val = readw(i2c_dev->base + REG_CR);
val |= CR_CPU_RDY;
writew(val, i2c_dev->base + REG_CR);
}
while (xfer_len < pmsg->len) {
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
500 * HZ / 1000);
if (wait_result == 0)
return -ETIMEDOUT;
ret = wmt_check_status(i2c_dev);
if (ret)
return ret;
xfer_len++;
val = readw(i2c_dev->base + REG_CSR);
if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
return -EIO;
}
if (pmsg->len == 0) {
val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
writew(val, i2c_dev->base + REG_CR);
break;
}
if (xfer_len == pmsg->len) {
if (last != 1)
writew(CR_ENABLE, i2c_dev->base + REG_CR);
} else {
writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
REG_CDR);
writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
}
}
return 0;
}
static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
int last)
{
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
u16 val, tcr_val;
int ret, wait_result;
u32 xfer_len = 0;
if (!(pmsg->flags & I2C_M_NOSTART)) {
ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
if (ret < 0)
return ret;
}
val = readw(i2c_dev->base + REG_CR);
val &= ~CR_TX_END;
writew(val, i2c_dev->base + REG_CR);
val = readw(i2c_dev->base + REG_CR);
val &= ~CR_TX_NEXT_NO_ACK;
writew(val, i2c_dev->base + REG_CR);
if (!(pmsg->flags & I2C_M_NOSTART)) {
val = readw(i2c_dev->base + REG_CR);
val |= CR_CPU_RDY;
writew(val, i2c_dev->base + REG_CR);
}
if (pmsg->len == 1) {
val = readw(i2c_dev->base + REG_CR);
val |= CR_TX_NEXT_NO_ACK;
writew(val, i2c_dev->base + REG_CR);
}
INIT_COMPLETION(i2c_dev->complete);
if (i2c_dev->mode == I2C_MODE_STANDARD)
tcr_val = TCR_STANDARD_MODE;
else
tcr_val = TCR_FAST_MODE;
tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
writew(tcr_val, i2c_dev->base + REG_TCR);
if (pmsg->flags & I2C_M_NOSTART) {
val = readw(i2c_dev->base + REG_CR);
val |= CR_CPU_RDY;
writew(val, i2c_dev->base + REG_CR);
}
while (xfer_len < pmsg->len) {
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
500 * HZ / 1000);
if (!wait_result)
return -ETIMEDOUT;
ret = wmt_check_status(i2c_dev);
if (ret)
return ret;
pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
xfer_len++;
if (xfer_len == pmsg->len - 1) {
val = readw(i2c_dev->base + REG_CR);
val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY);
writew(val, i2c_dev->base + REG_CR);
} else {
val = readw(i2c_dev->base + REG_CR);
val |= CR_CPU_RDY;
writew(val, i2c_dev->base + REG_CR);
}
}
return 0;
}
static int wmt_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[],
int num)
{
struct i2c_msg *pmsg;
int i, is_last;
int ret = 0;
for (i = 0; ret >= 0 && i < num; i++) {
is_last = ((i + 1) == num);
pmsg = &msgs[i];
if (pmsg->flags & I2C_M_RD)
ret = wmt_i2c_read(adap, pmsg, is_last);
else
ret = wmt_i2c_write(adap, pmsg, is_last);
}
return (ret < 0) ? ret : i;
}
static u32 wmt_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
}
static const struct i2c_algorithm wmt_i2c_algo = {
.master_xfer = wmt_i2c_xfer,
.functionality = wmt_i2c_func,
};
static irqreturn_t wmt_i2c_isr(int irq, void *data)
{
struct wmt_i2c_dev *i2c_dev = data;
/* save the status and write-clear it */
i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
complete(&i2c_dev->complete);
return IRQ_HANDLED;
}
static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
{
int err;
err = clk_prepare_enable(i2c_dev->clk);
if (err) {
dev_err(i2c_dev->dev, "failed to enable clock\n");
return err;
}
err = clk_set_rate(i2c_dev->clk, 20000000);
if (err) {
dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
return err;
}
writew(0, i2c_dev->base + REG_CR);
writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
writew(CR_ENABLE, i2c_dev->base + REG_CR);
readw(i2c_dev->base + REG_CSR); /* read clear */
writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
if (i2c_dev->mode == I2C_MODE_STANDARD)
writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
else
writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
return 0;
}
static int wmt_i2c_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct wmt_i2c_dev *i2c_dev;
struct i2c_adapter *adap;
struct resource *res;
int err;
u32 clk_rate;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev) {
dev_err(&pdev->dev, "device memory allocation failed\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c_dev->base))
return PTR_ERR(i2c_dev->base);
i2c_dev->irq = irq_of_parse_and_map(np, 0);
if (!i2c_dev->irq) {
dev_err(&pdev->dev, "irq missing or invalid\n");
return -EINVAL;
}
i2c_dev->clk = of_clk_get(np, 0);
if (IS_ERR(i2c_dev->clk)) {
dev_err(&pdev->dev, "unable to request clock\n");
return PTR_ERR(i2c_dev->clk);
}
i2c_dev->mode = I2C_MODE_STANDARD;
err = of_property_read_u32(np, "clock-frequency", &clk_rate);
if ((!err) && (clk_rate == 400000))
i2c_dev->mode = I2C_MODE_FAST;
i2c_dev->dev = &pdev->dev;
err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
"i2c", i2c_dev);
if (err) {
dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
return err;
}
adap = &i2c_dev->adapter;
i2c_set_adapdata(adap, i2c_dev);
strlcpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
adap->owner = THIS_MODULE;
adap->algo = &wmt_i2c_algo;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
init_completion(&i2c_dev->complete);
err = wmt_i2c_reset_hardware(i2c_dev);
if (err) {
dev_err(&pdev->dev, "error initializing hardware\n");
return err;
}
err = i2c_add_adapter(adap);
if (err) {
dev_err(&pdev->dev, "failed to add adapter\n");
return err;
}
platform_set_drvdata(pdev, i2c_dev);
of_i2c_register_devices(adap);
return 0;
}
static int wmt_i2c_remove(struct platform_device *pdev)
{
struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
/* Disable interrupts, clock and delete adapter */
writew(0, i2c_dev->base + REG_IMR);
clk_disable_unprepare(i2c_dev->clk);
i2c_del_adapter(&i2c_dev->adapter);
return 0;
}
static struct of_device_id wmt_i2c_dt_ids[] = {
{ .compatible = "wm,wm8505-i2c" },
{ /* Sentinel */ },
};
static struct platform_driver wmt_i2c_driver = {
.probe = wmt_i2c_probe,
.remove = wmt_i2c_remove,
.driver = {
.name = "wmt-i2c",
.owner = THIS_MODULE,
.of_match_table = wmt_i2c_dt_ids,
},
};
module_platform_driver(wmt_i2c_driver);
MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
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