Commit b4beb4bf authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus/i2c-3.2' of git://git.fluff.org/bjdooks/linux

* 'for-linus/i2c-3.2' of git://git.fluff.org/bjdooks/linux: (47 commits)
  i2c-s3c2410: Add device tree support
  i2c-s3c2410: Keep a copy of platform data and use it
  i2c-nomadik: cosmetic coding style corrections
  i2c-au1550: dev_pm_ops conversion
  i2c-au1550: increase timeout waiting for master done
  i2c-au1550: remove unused ack_timeout
  i2c-au1550: remove usage of volatile keyword
  i2c-tegra: __iomem annotation fix
  i2c-eg20t: Add initialize processing in case i2c-error occurs
  i2c-eg20t: Fix flag setting issue
  i2c-eg20t: add stop sequence in case wait-event timeout occurs
  i2c-eg20t: Separate error processing
  i2c-eg20t: Fix 10bit access issue
  i2c-eg20t: Modify returned value s32 to long
  i2c-eg20t: Fix bus-idle waiting issue
  i2c-designware: Fix PCI core warning on suspend/resume
  i2c-designware: Add runtime power management support
  i2c-designware: Add support for Designware core behind PCI devices.
  i2c-designware: Push all register reads/writes into the core code.
  i2c-designware: Support multiple cores using same ISR
  ...
parents f3c3f067 3945fe93
* Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MX
Required properties:
- compatible : Should be "fsl,<chip>-i2c"
- reg : Should contain I2C/HS-I2C registers location and length
- interrupts : Should contain I2C/HS-I2C interrupt
Optional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
The absence of the propoerty indicates the default frequency 100 kHz.
Examples:
i2c@83fc4000 { /* I2C2 on i.MX51 */
compatible = "fsl,imx51-i2c", "fsl,imx1-i2c";
reg = <0x83fc4000 0x4000>;
interrupts = <63>;
};
i2c@70038000 { /* HS-I2C on i.MX51 */
compatible = "fsl,imx51-i2c", "fsl,imx1-i2c";
reg = <0x70038000 0x4000>;
interrupts = <64>;
clock-frequency = <400000>;
};
* Samsung's I2C controller
The Samsung's I2C controller is used to interface with I2C devices.
Required properties:
- compatible: value should be either of the following.
(a) "samsung, s3c2410-i2c", for i2c compatible with s3c2410 i2c.
(b) "samsung, s3c2440-i2c", for i2c compatible with s3c2440 i2c.
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
- samsung,i2c-sda-delay: Delay (in ns) applied to data line (SDA) edges.
- gpios: The order of the gpios should be the following: <SDA, SCL>.
The gpio specifier depends on the gpio controller.
Optional properties:
- samsung,i2c-slave-addr: Slave address in multi-master enviroment. If not
specified, default value is 0.
- samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not
specified, the default value in Hz is 100000.
Example:
i2c@13870000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x13870000 0x100>;
interrupts = <345>;
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <100000>;
gpios = <&gpd1 2 0 /* SDA */
&gpd1 3 0 /* SCL */>;
#address-cells = <1>;
#size-cells = <0>;
wm8994@1a {
compatible = "wlf,wm8994";
reg = <0x1a>;
};
};
...@@ -11,14 +11,10 @@ ...@@ -11,14 +11,10 @@
/** /**
* struct imxi2c_platform_data - structure of platform data for MXC I2C driver * struct imxi2c_platform_data - structure of platform data for MXC I2C driver
* @init: Initialise gpio's and other board specific things
* @exit: Free everything initialised by @init
* @bitrate: Bus speed measured in Hz * @bitrate: Bus speed measured in Hz
* *
**/ **/
struct imxi2c_platform_data { struct imxi2c_platform_data {
int (*init)(struct device *dev);
void (*exit)(struct device *dev);
int bitrate; int bitrate;
}; };
......
...@@ -108,6 +108,22 @@ static inline int omap1_i2c_add_bus(int bus_id) ...@@ -108,6 +108,22 @@ static inline int omap1_i2c_add_bus(int bus_id)
res[1].start = INT_I2C; res[1].start = INT_I2C;
pdata = &i2c_pdata[bus_id - 1]; pdata = &i2c_pdata[bus_id - 1];
/* all OMAP1 have IP version 1 register set */
pdata->rev = OMAP_I2C_IP_VERSION_1;
/* all OMAP1 I2C are implemented like this */
pdata->flags = OMAP_I2C_FLAG_NO_FIFO |
OMAP_I2C_FLAG_SIMPLE_CLOCK |
OMAP_I2C_FLAG_16BIT_DATA_REG |
OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK;
/* how the cpu bus is wired up differs for 7xx only */
if (cpu_is_omap7xx())
pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_1;
else
pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2;
return platform_device_register(pdev); return platform_device_register(pdev);
} }
...@@ -138,6 +154,7 @@ static inline int omap2_i2c_add_bus(int bus_id) ...@@ -138,6 +154,7 @@ static inline int omap2_i2c_add_bus(int bus_id)
struct omap_device *od; struct omap_device *od;
char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN]; char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN];
struct omap_i2c_bus_platform_data *pdata; struct omap_i2c_bus_platform_data *pdata;
struct omap_i2c_dev_attr *dev_attr;
omap2_i2c_mux_pins(bus_id); omap2_i2c_mux_pins(bus_id);
...@@ -151,6 +168,16 @@ static inline int omap2_i2c_add_bus(int bus_id) ...@@ -151,6 +168,16 @@ static inline int omap2_i2c_add_bus(int bus_id)
} }
pdata = &i2c_pdata[bus_id - 1]; pdata = &i2c_pdata[bus_id - 1];
/*
* pass the hwmod class's CPU-specific knowledge of I2C IP revision in
* use, and functionality implementation flags, up to the OMAP I2C
* driver via platform data
*/
pdata->rev = oh->class->rev;
dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
pdata->flags = dev_attr->flags;
/* /*
* When waiting for completion of a i2c transfer, we need to * When waiting for completion of a i2c transfer, we need to
* set a wake up latency constraint for the MPU. This is to * set a wake up latency constraint for the MPU. This is to
......
...@@ -394,19 +394,6 @@ typedef struct psc_spi { ...@@ -394,19 +394,6 @@ typedef struct psc_spi {
#define PSC_SPITXRX_LC (1 << 29) #define PSC_SPITXRX_LC (1 << 29)
#define PSC_SPITXRX_SR (1 << 28) #define PSC_SPITXRX_SR (1 << 28)
/* PSC in SMBus (I2C) Mode. */
typedef struct psc_smb {
u32 psc_sel;
u32 psc_ctrl;
u32 psc_smbcfg;
u32 psc_smbmsk;
u32 psc_smbpcr;
u32 psc_smbstat;
u32 psc_smbevnt;
u32 psc_smbtxrx;
u32 psc_smbtmr;
} psc_smb_t;
/* SMBus Config Register. */ /* SMBus Config Register. */
#define PSC_SMBCFG_RT_MASK (3 << 30) #define PSC_SMBCFG_RT_MASK (3 << 30)
#define PSC_SMBCFG_RT_FIFO1 (0 << 30) #define PSC_SMBCFG_RT_FIFO1 (0 << 30)
......
...@@ -350,15 +350,25 @@ config I2C_DAVINCI ...@@ -350,15 +350,25 @@ config I2C_DAVINCI
devices such as DaVinci NIC. devices such as DaVinci NIC.
For details please see http://www.ti.com/davinci For details please see http://www.ti.com/davinci
config I2C_DESIGNWARE config I2C_DESIGNWARE_PLATFORM
tristate "Synopsys DesignWare" tristate "Synopsys DesignWare Platfrom"
depends on HAVE_CLK depends on HAVE_CLK
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter. Only master mode is supported. Synopsys DesignWare I2C adapter. Only master mode is supported.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-designware. will be called i2c-designware-platform.
config I2C_DESIGNWARE_PCI
tristate "Synopsys DesignWare PCI"
depends on PCI
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter. Only master mode is supported.
This driver can also be built as a module. If so, the module
will be called i2c-designware-pci.
config I2C_GPIO config I2C_GPIO
tristate "GPIO-based bitbanging I2C" tristate "GPIO-based bitbanging I2C"
......
...@@ -33,7 +33,10 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o ...@@ -33,7 +33,10 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
......
This diff is collapsed.
...@@ -631,7 +631,7 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev) ...@@ -631,7 +631,7 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev)
struct bfin_twi_iface *iface = platform_get_drvdata(pdev); struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
int rc = request_irq(iface->irq, bfin_twi_interrupt_entry, int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
IRQF_DISABLED, pdev->name, iface); 0, pdev->name, iface);
if (rc) { if (rc) {
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
return -ENODEV; return -ENODEV;
...@@ -702,7 +702,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) ...@@ -702,7 +702,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
} }
rc = request_irq(iface->irq, bfin_twi_interrupt_entry, rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
IRQF_DISABLED, pdev->name, iface); 0, pdev->name, iface);
if (rc) { if (rc) {
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
rc = -ENODEV; rc = -ENODEV;
......
/*
* Synopsys DesignWare I2C adapter driver (master only).
*
* Based on the TI DAVINCI I2C adapter driver.
*
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
*
* ----------------------------------------------------------------------------
*
* 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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* ----------------------------------------------------------------------------
*
*/
#define DW_IC_CON_MASTER 0x1
#define DW_IC_CON_SPEED_STD 0x2
#define DW_IC_CON_SPEED_FAST 0x4
#define DW_IC_CON_10BITADDR_MASTER 0x10
#define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40
/**
* struct dw_i2c_dev - private i2c-designware data
* @dev: driver model device node
* @base: IO registers pointer
* @cmd_complete: tx completion indicator
* @lock: protect this struct and IO registers
* @clk: input reference clock
* @cmd_err: run time hadware error code
* @msgs: points to an array of messages currently being transfered
* @msgs_num: the number of elements in msgs
* @msg_write_idx: the element index of the current tx message in the msgs
* array
* @tx_buf_len: the length of the current tx buffer
* @tx_buf: the current tx buffer
* @msg_read_idx: the element index of the current rx message in the msgs
* array
* @rx_buf_len: the length of the current rx buffer
* @rx_buf: the current rx buffer
* @msg_err: error status of the current transfer
* @status: i2c master status, one of STATUS_*
* @abort_source: copy of the TX_ABRT_SOURCE register
* @irq: interrupt number for the i2c master
* @adapter: i2c subsystem adapter node
* @tx_fifo_depth: depth of the hardware tx fifo
* @rx_fifo_depth: depth of the hardware rx fifo
*/
struct dw_i2c_dev {
struct device *dev;
void __iomem *base;
struct completion cmd_complete;
struct mutex lock;
struct clk *clk;
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
struct dw_pci_controller *controller;
int cmd_err;
struct i2c_msg *msgs;
int msgs_num;
int msg_write_idx;
u32 tx_buf_len;
u8 *tx_buf;
int msg_read_idx;
u32 rx_buf_len;
u8 *rx_buf;
int msg_err;
unsigned int status;
u32 abort_source;
int irq;
int swab;
struct i2c_adapter adapter;
u32 functionality;
u32 master_cfg;
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
};
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);
/*
* Synopsys DesignWare I2C adapter driver (master only).
*
* Based on the TI DAVINCI I2C adapter driver.
*
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
* Copyright (C) 2011 Intel corporation.
*
* ----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; 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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* ----------------------------------------------------------------------------
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include "i2c-designware-core.h"
#define DRIVER_NAME "i2c-designware-pci"
enum dw_pci_ctl_id_t {
moorestown_0,
moorestown_1,
moorestown_2,
medfield_0,
medfield_1,
medfield_2,
medfield_3,
medfield_4,
medfield_5,
};
struct dw_pci_controller {
u32 bus_num;
u32 bus_cfg;
u32 tx_fifo_depth;
u32 rx_fifo_depth;
u32 clk_khz;
};
#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
DW_IC_CON_SLAVE_DISABLE | \
DW_IC_CON_RESTART_EN)
static struct dw_pci_controller dw_pci_controllers[] = {
[moorestown_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[moorestown_1] = {
.bus_num = 1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[moorestown_2] = {
.bus_num = 2,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_1] = {
.bus_num = 1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_2] = {
.bus_num = 2,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_3] = {
.bus_num = 3,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_4] = {
.bus_num = 4,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_5] = {
.bus_num = 5,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
};
static struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
static int i2c_dw_pci_suspend(struct device *dev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
int err;
i2c_dw_disable(i2c);
err = pci_save_state(pdev);
if (err) {
dev_err(&pdev->dev, "pci_save_state failed\n");
return err;
}
err = pci_set_power_state(pdev, PCI_D3hot);
if (err) {
dev_err(&pdev->dev, "pci_set_power_state failed\n");
return err;
}
return 0;
}
static int i2c_dw_pci_resume(struct device *dev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
int err;
u32 enabled;
enabled = i2c_dw_is_enabled(i2c);
if (enabled)
return 0;
err = pci_set_power_state(pdev, PCI_D0);
if (err) {
dev_err(&pdev->dev, "pci_set_power_state() failed\n");
return err;
}
pci_restore_state(pdev);
i2c_dw_init(i2c);
i2c_dw_enable(i2c);
return 0;
}
static int i2c_dw_pci_runtime_idle(struct device *dev)
{
int err = pm_schedule_suspend(dev, 500);
dev_dbg(dev, "runtime_idle called\n");
if (err != 0)
return 0;
return -EBUSY;
}
static const struct dev_pm_ops i2c_dw_pm_ops = {
.resume = i2c_dw_pci_resume,
.suspend = i2c_dw_pci_suspend,
SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
i2c_dw_pci_runtime_idle)
};
static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
return dev->controller->clk_khz;
}
static int __devinit i2c_dw_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
unsigned long start, len;
void __iomem *base;
int r;
struct dw_pci_controller *controller;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n",
id->driver_data);
return -EINVAL;
}
controller = &dw_pci_controllers[id->driver_data];
r = pci_enable_device(pdev);
if (r) {
dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
r);
goto exit;
}
/* Determine the address of the I2C area */
start = pci_resource_start(pdev, 0);
len = pci_resource_len(pdev, 0);
if (!start || len == 0) {
dev_err(&pdev->dev, "base address not set\n");
r = -ENODEV;
goto exit;
}
r = pci_request_region(pdev, 0, DRIVER_NAME);
if (r) {
dev_err(&pdev->dev, "failed to request I2C region "
"0x%lx-0x%lx\n", start,
(unsigned long)pci_resource_end(pdev, 0));
goto exit;
}
base = ioremap_nocache(start, len);
if (!base) {
dev_err(&pdev->dev, "I/O memory remapping failed\n");
r = -ENOMEM;
goto err_release_region;
}
dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
if (!dev) {
r = -ENOMEM;
goto err_release_region;
}
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 = base;
dev->dev = get_device(&pdev->dev);
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
dev->master_cfg = controller->bus_cfg;
pci_set_drvdata(pdev, dev);
dev->tx_fifo_depth = controller->tx_fifo_depth;
dev->rx_fifo_depth = controller->rx_fifo_depth;
r = i2c_dw_init(dev);
if (r)
goto err_iounmap;
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;
adap->nr = controller->bus_num;
snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
adap->nr);
r = request_irq(pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev);
if (r) {
dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
goto err_iounmap;
}
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");
goto err_free_irq;
}
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
return 0;
err_free_irq:
free_irq(pdev->irq, dev);
err_iounmap:
iounmap(dev->base);
pci_set_drvdata(pdev, NULL);
put_device(&pdev->dev);
kfree(dev);
err_release_region:
pci_release_region(pdev, 0);
exit:
return r;
}
static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev)
{
struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
i2c_dw_disable(dev);
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
pci_set_drvdata(pdev, NULL);
i2c_del_adapter(&dev->adapter);
put_device(&pdev->dev);
free_irq(dev->irq, dev);
kfree(dev);
pci_release_region(pdev, 0);
}
/* work with hotplug and coldplug */
MODULE_ALIAS("i2c_designware-pci");
DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
/* Moorestown */
{ PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
{ PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
{ PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
/* Medfield */
{ PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
{ PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
{ PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
static struct pci_driver dw_i2c_driver = {
.name = DRIVER_NAME,
.id_table = i2_designware_pci_ids,
.probe = i2c_dw_pci_probe,
.remove = __devexit_p(i2c_dw_pci_remove),
.driver = {
.pm = &i2c_dw_pm_ops,
},
};
static int __init dw_i2c_init_driver(void)
{
return pci_register_driver(&dw_i2c_driver);
}
module_init(dw_i2c_init_driver);
static void __exit dw_i2c_exit_driver(void)
{
pci_unregister_driver(&dw_i2c_driver);
}
module_exit(dw_i2c_exit_driver);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
MODULE_LICENSE("GPL");
/*
* Synopsys DesignWare I2C adapter driver (master only).
*
* Based on the TI DAVINCI I2C adapter driver.
*
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
*
* ----------------------------------------------------------------------------
*
* 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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* ----------------------------------------------------------------------------
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.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;
}
static int __devinit dw_i2c_probe(struct platform_device *pdev)
{
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem, *ioarea;
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");
return irq; /* -ENXIO */
}
ioarea = request_mem_region(mem->start, resource_size(mem),
pdev->name);
if (!ioarea) {
dev_err(&pdev->dev, "I2C region already claimed\n");
return -EBUSY;
}
dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
if (!dev) {
r = -ENOMEM;
goto err_release_region;
}
init_completion(&dev->cmd_complete);
mutex_init(&dev->lock);
dev->dev = get_device(&pdev->dev);
dev->irq = irq;
platform_set_drvdata(pdev, dev);
dev->clk = clk_get(&pdev->dev, NULL);
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
if (IS_ERR(dev->clk)) {
r = -ENODEV;
goto err_free_mem;
}
clk_enable(dev->clk);
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
dev->base = ioremap(mem->start, resource_size(mem));
if (dev->base == NULL) {
dev_err(&pdev->dev, "failure mapping io resources\n");
r = -EBUSY;
goto err_unuse_clocks;
}
{
u32 param1 = i2c_dw_read_comp_param(dev);
dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
}
r = i2c_dw_init(dev);
if (r)
goto err_iounmap;
i2c_dw_disable_int(dev);
r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
if (r) {
dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
goto err_iounmap;
}
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON;
strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
sizeof(adap->name));
adap->algo = &i2c_dw_algo;
adap->dev.parent = &pdev->dev;
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
if (r) {
dev_err(&pdev->dev, "failure adding adapter\n");
goto err_free_irq;
}
return 0;
err_free_irq:
free_irq(dev->irq, dev);
err_iounmap:
iounmap(dev->base);
err_unuse_clocks:
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
err_free_mem:
platform_set_drvdata(pdev, NULL);
put_device(&pdev->dev);
kfree(dev);
err_release_region:
release_mem_region(mem->start, resource_size(mem));
return r;
}
static int __devexit dw_i2c_remove(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
struct resource *mem;
platform_set_drvdata(pdev, NULL);
i2c_del_adapter(&dev->adapter);
put_device(&pdev->dev);
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
i2c_dw_disable(dev);
free_irq(dev->irq, dev);
kfree(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, resource_size(mem));
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
static struct platform_driver dw_i2c_driver = {
.remove = __devexit_p(dw_i2c_remove),
.driver = {
.name = "i2c_designware",
.owner = THIS_MODULE,
},
};
static int __init dw_i2c_init_driver(void)
{
return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
}
module_init(dw_i2c_init_driver);
static void __exit dw_i2c_exit_driver(void)
{
platform_driver_unregister(&dw_i2c_driver);
}
module_exit(dw_i2c_exit_driver);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
MODULE_LICENSE("GPL");
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#define TEN_BIT_ADDR_DEFAULT 0xF000 #define TEN_BIT_ADDR_DEFAULT 0xF000
#define TEN_BIT_ADDR_MASK 0xF0 #define TEN_BIT_ADDR_MASK 0xF0
#define PCH_START 0x0020 #define PCH_START 0x0020
#define PCH_RESTART 0x0004
#define PCH_ESR_START 0x0001 #define PCH_ESR_START 0x0001
#define PCH_BUFF_START 0x1 #define PCH_BUFF_START 0x1
#define PCH_REPSTART 0x0004 #define PCH_REPSTART 0x0004
...@@ -273,23 +274,24 @@ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, ...@@ -273,23 +274,24 @@ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
s32 timeout) s32 timeout)
{ {
void __iomem *p = adap->pch_base_address; void __iomem *p = adap->pch_base_address;
ktime_t ns_val;
if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
return 0;
/* MAX timeout value is timeout*1000*1000nsec */ /* MAX timeout value is timeout*1000*1000nsec */
ktime_t ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000); ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
do { do {
if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
break;
msleep(20); msleep(20);
if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
return 0;
} while (ktime_lt(ktime_get(), ns_val)); } while (ktime_lt(ktime_get(), ns_val));
pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR)); pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
if (timeout == 0) {
pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME); pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
return -ETIME; pch_i2c_init(adap);
}
return 0; return -ETIME;
} }
/** /**
...@@ -311,21 +313,19 @@ static void pch_i2c_start(struct i2c_algo_pch_data *adap) ...@@ -311,21 +313,19 @@ static void pch_i2c_start(struct i2c_algo_pch_data *adap)
*/ */
static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap) static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap)
{ {
s32 ret; long ret;
ret = wait_event_timeout(pch_event, ret = wait_event_timeout(pch_event,
(adap->pch_event_flag != 0), msecs_to_jiffies(50)); (adap->pch_event_flag != 0), msecs_to_jiffies(50));
if (ret < 0) {
pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
return ret;
}
if (ret == 0) { if (ret == 0) {
pch_err(adap, "timeout: %x\n", adap->pch_event_flag); pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
adap->pch_event_flag = 0;
return -ETIMEDOUT; return -ETIMEDOUT;
} }
if (adap->pch_event_flag & I2C_ERROR_MASK) { if (adap->pch_event_flag & I2C_ERROR_MASK) {
pch_err(adap, "error bits set: %x\n", adap->pch_event_flag); pch_err(adap, "error bits set: %x\n", adap->pch_event_flag);
adap->pch_event_flag = 0;
return -EIO; return -EIO;
} }
...@@ -394,6 +394,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, ...@@ -394,6 +394,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
u32 addr_2_msb; u32 addr_2_msb;
u32 addr_8_lsb; u32 addr_8_lsb;
s32 wrcount; s32 wrcount;
s32 rtn;
void __iomem *p = adap->pch_base_address; void __iomem *p = adap->pch_base_address;
length = msgs->len; length = msgs->len;
...@@ -412,15 +413,29 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, ...@@ -412,15 +413,29 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
} }
if (msgs->flags & I2C_M_TEN) { if (msgs->flags & I2C_M_TEN) {
addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06;
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
if (first) if (first)
pch_i2c_start(adap); pch_i2c_start(adap);
if (pch_i2c_wait_for_xfer_complete(adap) == 0 &&
pch_i2c_getack(adap) == 0) { rtn = pch_i2c_wait_for_xfer_complete(adap);
if (rtn == 0) {
if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave address"
"setting\n");
return -EIO;
}
addr_8_lsb = (addr & I2C_ADDR_MSK); addr_8_lsb = (addr & I2C_ADDR_MSK);
iowrite32(addr_8_lsb, p + PCH_I2CDR); iowrite32(addr_8_lsb, p + PCH_I2CDR);
} else { } else if (rtn == -EIO) { /* Arbitration Lost */
pch_err(adap, "Lost Arbitration\n");
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMAL_BIT);
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMIF_BIT);
pch_i2c_init(adap);
return -EAGAIN;
} else { /* wait-event timeout */
pch_i2c_stop(adap); pch_i2c_stop(adap);
return -ETIME; return -ETIME;
} }
...@@ -431,30 +446,51 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, ...@@ -431,30 +446,51 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
pch_i2c_start(adap); pch_i2c_start(adap);
} }
if ((pch_i2c_wait_for_xfer_complete(adap) == 0) && rtn = pch_i2c_wait_for_xfer_complete(adap);
(pch_i2c_getack(adap) == 0)) { if (rtn == 0) {
if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave address"
"setting\n");
return -EIO;
}
} else if (rtn == -EIO) { /* Arbitration Lost */
pch_err(adap, "Lost Arbitration\n");
pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
pch_i2c_init(adap);
return -EAGAIN;
} else { /* wait-event timeout */
pch_i2c_stop(adap);
return -ETIME;
}
for (wrcount = 0; wrcount < length; ++wrcount) { for (wrcount = 0; wrcount < length; ++wrcount) {
/* write buffer value to I2C data register */ /* write buffer value to I2C data register */
iowrite32(buf[wrcount], p + PCH_I2CDR); iowrite32(buf[wrcount], p + PCH_I2CDR);
pch_dbg(adap, "writing %x to Data register\n", pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]);
buf[wrcount]);
if (pch_i2c_wait_for_xfer_complete(adap) != 0)
return -ETIME;
if (pch_i2c_getack(adap)) rtn = pch_i2c_wait_for_xfer_complete(adap);
if (rtn == 0) {
if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave address"
"setting\n");
return -EIO; return -EIO;
} }
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMCF_BIT);
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMIF_BIT);
} else { /* wait-event timeout */
pch_i2c_stop(adap);
return -ETIME;
}
}
/* check if this is the last message */ /* check if this is the last message */
if (last) if (last)
pch_i2c_stop(adap); pch_i2c_stop(adap);
else else
pch_i2c_repstart(adap); pch_i2c_repstart(adap);
} else {
pch_i2c_stop(adap);
return -EIO;
}
pch_dbg(adap, "return=%d\n", wrcount); pch_dbg(adap, "return=%d\n", wrcount);
...@@ -483,6 +519,19 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap) ...@@ -483,6 +519,19 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK); pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
} }
/**
* pch_i2c_restart() - Generate I2C restart condition in normal mode.
* @adap: Pointer to struct i2c_algo_pch_data.
*
* Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA.
*/
static void pch_i2c_restart(struct i2c_algo_pch_data *adap)
{
void __iomem *p = adap->pch_base_address;
pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART);
}
/** /**
* pch_i2c_readbytes() - read data from I2C bus in normal mode. * pch_i2c_readbytes() - read data from I2C bus in normal mode.
* @i2c_adap: Pointer to the struct i2c_adapter. * @i2c_adap: Pointer to the struct i2c_adapter.
...@@ -500,7 +549,9 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, ...@@ -500,7 +549,9 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
u32 length; u32 length;
u32 addr; u32 addr;
u32 addr_2_msb; u32 addr_2_msb;
u32 addr_8_lsb;
void __iomem *p = adap->pch_base_address; void __iomem *p = adap->pch_base_address;
s32 rtn;
length = msgs->len; length = msgs->len;
buf = msgs->buf; buf = msgs->buf;
...@@ -515,9 +566,55 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, ...@@ -515,9 +566,55 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
} }
if (msgs->flags & I2C_M_TEN) { if (msgs->flags & I2C_M_TEN) {
addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD)); addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
if (first)
pch_i2c_start(adap);
rtn = pch_i2c_wait_for_xfer_complete(adap);
if (rtn == 0) {
if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave address"
"setting\n");
return -EIO;
}
addr_8_lsb = (addr & I2C_ADDR_MSK);
iowrite32(addr_8_lsb, p + PCH_I2CDR);
} else if (rtn == -EIO) { /* Arbitration Lost */
pch_err(adap, "Lost Arbitration\n");
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMAL_BIT);
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMIF_BIT);
pch_i2c_init(adap);
return -EAGAIN;
} else { /* wait-event timeout */
pch_i2c_stop(adap);
return -ETIME;
}
pch_i2c_restart(adap);
rtn = pch_i2c_wait_for_xfer_complete(adap);
if (rtn == 0) {
if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave address"
"setting\n");
return -EIO;
}
addr_2_msb |= I2C_RD;
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK,
p + PCH_I2CDR);
} else if (rtn == -EIO) { /* Arbitration Lost */
pch_err(adap, "Lost Arbitration\n");
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMAL_BIT);
pch_clrbit(adap->pch_base_address, PCH_I2CSR,
I2CMIF_BIT);
pch_i2c_init(adap);
return -EAGAIN;
} else { /* wait-event timeout */
pch_i2c_stop(adap);
return -ETIME;
}
} else { } else {
/* 7 address bits + R/W bit */ /* 7 address bits + R/W bit */
addr = (((addr) << 1) | (I2C_RD)); addr = (((addr) << 1) | (I2C_RD));
...@@ -528,9 +625,23 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, ...@@ -528,9 +625,23 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
if (first) if (first)
pch_i2c_start(adap); pch_i2c_start(adap);
if ((pch_i2c_wait_for_xfer_complete(adap) == 0) && rtn = pch_i2c_wait_for_xfer_complete(adap);
(pch_i2c_getack(adap) == 0)) { if (rtn == 0) {
pch_dbg(adap, "return %d\n", 0); if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave address"
"setting\n");
return -EIO;
}
} else if (rtn == -EIO) { /* Arbitration Lost */
pch_err(adap, "Lost Arbitration\n");
pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
pch_i2c_init(adap);
return -EAGAIN;
} else { /* wait-event timeout */
pch_i2c_stop(adap);
return -ETIME;
}
if (length == 0) { if (length == 0) {
pch_i2c_stop(adap); pch_i2c_stop(adap);
...@@ -549,35 +660,46 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, ...@@ -549,35 +660,46 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
if (loop != 1) if (loop != 1)
read_index++; read_index++;
if (pch_i2c_wait_for_xfer_complete(adap) != 0) { rtn = pch_i2c_wait_for_xfer_complete(adap);
if (rtn == 0) {
if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave"
"address setting\n");
return -EIO;
}
} else { /* wait-event timeout */
pch_i2c_stop(adap); pch_i2c_stop(adap);
return -ETIME; return -ETIME;
} }
} /* end for */ } /* end for */
pch_i2c_sendnack(adap); pch_i2c_sendnack(adap);
buf[read_index] = ioread32(p + PCH_I2CDR); buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */
if (length != 1) if (length != 1)
read_index++; read_index++;
if (pch_i2c_wait_for_xfer_complete(adap) == 0) { rtn = pch_i2c_wait_for_xfer_complete(adap);
if (rtn == 0) {
if (pch_i2c_getack(adap)) {
pch_dbg(adap, "Receive NACK for slave"
"address setting\n");
return -EIO;
}
} else { /* wait-event timeout */
pch_i2c_stop(adap);
return -ETIME;
}
if (last) if (last)
pch_i2c_stop(adap); pch_i2c_stop(adap);
else else
pch_i2c_repstart(adap); pch_i2c_repstart(adap);
buf[read_index++] = ioread32(p + PCH_I2CDR); buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */
count = read_index; count = read_index;
} else {
count = -ETIME;
}
}
} else {
count = -ETIME;
pch_i2c_stop(adap);
} }
return count; return count;
......
...@@ -387,7 +387,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev) ...@@ -387,7 +387,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev)
dev->irq = 0; dev->irq = 0;
if (dev->irq) { if (dev->irq) {
ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED, ret = request_irq(dev->irq, highlander_i2c_irq, 0,
pdev->name, dev); pdev->name, dev);
if (unlikely(ret)) if (unlikely(ret))
goto err_unmap; goto err_unmap;
......
...@@ -48,6 +48,9 @@ ...@@ -48,6 +48,9 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/hardware.h> #include <mach/hardware.h>
...@@ -125,6 +128,11 @@ struct imx_i2c_struct { ...@@ -125,6 +128,11 @@ struct imx_i2c_struct {
unsigned int ifdr; /* IMX_I2C_IFDR */ unsigned int ifdr; /* IMX_I2C_IFDR */
}; };
static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", },
{ /* sentinel */ }
};
/** Functions for IMX I2C adapter driver *************************************** /** Functions for IMX I2C adapter driver ***************************************
*******************************************************************************/ *******************************************************************************/
...@@ -466,10 +474,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev) ...@@ -466,10 +474,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
{ {
struct imx_i2c_struct *i2c_imx; struct imx_i2c_struct *i2c_imx;
struct resource *res; struct resource *res;
struct imxi2c_platform_data *pdata; struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
void __iomem *base; void __iomem *base;
resource_size_t res_size; resource_size_t res_size;
int irq; int irq, bitrate;
int ret; int ret;
dev_dbg(&pdev->dev, "<%s>\n", __func__); dev_dbg(&pdev->dev, "<%s>\n", __func__);
...@@ -485,19 +493,11 @@ static int __init i2c_imx_probe(struct platform_device *pdev) ...@@ -485,19 +493,11 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
return -ENOENT; return -ENOENT;
} }
pdata = pdev->dev.platform_data;
if (pdata && pdata->init) {
ret = pdata->init(&pdev->dev);
if (ret)
return ret;
}
res_size = resource_size(res); res_size = resource_size(res);
if (!request_mem_region(res->start, res_size, DRIVER_NAME)) { if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
ret = -EBUSY; dev_err(&pdev->dev, "request_mem_region failed\n");
goto fail0; return -EBUSY;
} }
base = ioremap(res->start, res_size); base = ioremap(res->start, res_size);
...@@ -520,6 +520,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev) ...@@ -520,6 +520,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.algo = &i2c_imx_algo; i2c_imx->adapter.algo = &i2c_imx_algo;
i2c_imx->adapter.dev.parent = &pdev->dev; i2c_imx->adapter.dev.parent = &pdev->dev;
i2c_imx->adapter.nr = pdev->id; i2c_imx->adapter.nr = pdev->id;
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->irq = irq; i2c_imx->irq = irq;
i2c_imx->base = base; i2c_imx->base = base;
i2c_imx->res = res; i2c_imx->res = res;
...@@ -546,10 +547,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev) ...@@ -546,10 +547,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
/* Set up clock divider */ /* Set up clock divider */
if (pdata && pdata->bitrate) bitrate = IMX_I2C_BIT_RATE;
i2c_imx_set_clk(i2c_imx, pdata->bitrate); ret = of_property_read_u32(pdev->dev.of_node,
else "clock-frequency", &bitrate);
i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE); if (ret < 0 && pdata && pdata->bitrate)
bitrate = pdata->bitrate;
i2c_imx_set_clk(i2c_imx, bitrate);
/* Set up chip registers to defaults */ /* Set up chip registers to defaults */
writeb(0, i2c_imx->base + IMX_I2C_I2CR); writeb(0, i2c_imx->base + IMX_I2C_I2CR);
...@@ -562,6 +565,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev) ...@@ -562,6 +565,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
goto fail5; goto fail5;
} }
of_i2c_register_devices(&i2c_imx->adapter);
/* Set up platform driver data */ /* Set up platform driver data */
platform_set_drvdata(pdev, i2c_imx); platform_set_drvdata(pdev, i2c_imx);
...@@ -586,16 +591,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev) ...@@ -586,16 +591,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
iounmap(base); iounmap(base);
fail1: fail1:
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
fail0:
if (pdata && pdata->exit)
pdata->exit(&pdev->dev);
return ret; /* Return error number */ return ret; /* Return error number */
} }
static int __exit i2c_imx_remove(struct platform_device *pdev) static int __exit i2c_imx_remove(struct platform_device *pdev)
{ {
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev); struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
/* remove adapter */ /* remove adapter */
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
...@@ -611,10 +612,6 @@ static int __exit i2c_imx_remove(struct platform_device *pdev) ...@@ -611,10 +612,6 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
writeb(0, i2c_imx->base + IMX_I2C_I2CR); writeb(0, i2c_imx->base + IMX_I2C_I2CR);
writeb(0, i2c_imx->base + IMX_I2C_I2SR); writeb(0, i2c_imx->base + IMX_I2C_I2SR);
/* Shut down hardware */
if (pdata && pdata->exit)
pdata->exit(&pdev->dev);
clk_put(i2c_imx->clk); clk_put(i2c_imx->clk);
iounmap(i2c_imx->base); iounmap(i2c_imx->base);
...@@ -628,6 +625,7 @@ static struct platform_driver i2c_imx_driver = { ...@@ -628,6 +625,7 @@ static struct platform_driver i2c_imx_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = i2c_imx_dt_ids,
} }
}; };
......
...@@ -135,19 +135,19 @@ struct i2c_nmk_client { ...@@ -135,19 +135,19 @@ struct i2c_nmk_client {
}; };
/** /**
* struct nmk_i2c_dev - private data structure of the controller * struct nmk_i2c_dev - private data structure of the controller.
* @pdev: parent platform device * @pdev: parent platform device.
* @adap: corresponding I2C adapter * @adap: corresponding I2C adapter.
* @irq: interrupt line for the controller * @irq: interrupt line for the controller.
* @virtbase: virtual io memory area * @virtbase: virtual io memory area.
* @clk: hardware i2c block clock * @clk: hardware i2c block clock.
* @cfg: machine provided controller configuration * @cfg: machine provided controller configuration.
* @cli: holder of client specific data * @cli: holder of client specific data.
* @stop: stop condition * @stop: stop condition.
* @xfer_complete: acknowledge completion for a I2C message * @xfer_complete: acknowledge completion for a I2C message.
* @result: controller propogated result * @result: controller propogated result.
* @regulator: pointer to i2c regulator * @regulator: pointer to i2c regulator.
* @busy: Busy doing transfer * @busy: Busy doing transfer.
*/ */
struct nmk_i2c_dev { struct nmk_i2c_dev {
struct platform_device *pdev; struct platform_device *pdev;
...@@ -217,8 +217,9 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) ...@@ -217,8 +217,9 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
} }
} }
dev_err(&dev->pdev->dev, "flushing operation timed out " dev_err(&dev->pdev->dev,
"giving up after %d attempts", LOOP_ATTEMPTS); "flushing operation timed out giving up after %d attempts",
LOOP_ATTEMPTS);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -363,8 +364,8 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) ...@@ -363,8 +364,8 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* and high speed (up to 3.4 Mb/s) * and high speed (up to 3.4 Mb/s)
*/ */
if (dev->cfg.sm > I2C_FREQ_MODE_FAST) { if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
dev_err(&dev->pdev->dev, "do not support this mode " dev_err(&dev->pdev->dev,
"defaulting to std. mode\n"); "do not support this mode defaulting to std. mode\n");
brcr2 = i2c_clk/(100000 * 2) & 0xffff; brcr2 = i2c_clk/(100000 * 2) & 0xffff;
writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
writel(I2C_FREQ_MODE_STANDARD << 4, writel(I2C_FREQ_MODE_STANDARD << 4,
...@@ -423,7 +424,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) ...@@ -423,7 +424,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
if (timeout < 0) { if (timeout < 0) {
dev_err(&dev->pdev->dev, dev_err(&dev->pdev->dev,
"wait_for_completion_timeout" "wait_for_completion_timeout "
"returned %d waiting for event\n", timeout); "returned %d waiting for event\n", timeout);
status = timeout; status = timeout;
} }
...@@ -556,8 +557,8 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) ...@@ -556,8 +557,8 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
if (((i2c_sr >> 2) & 0x3) == 0x3) { if (((i2c_sr >> 2) & 0x3) == 0x3) {
/* get the abort cause */ /* get the abort cause */
cause = (i2c_sr >> 4) & 0x7; cause = (i2c_sr >> 4) & 0x7;
dev_err(&dev->pdev->dev, "%s\n", cause dev_err(&dev->pdev->dev, "%s\n",
>= ARRAY_SIZE(abort_causes) ? cause >= ARRAY_SIZE(abort_causes) ?
"unknown reason" : "unknown reason" :
abort_causes[cause]); abort_causes[cause]);
} }
...@@ -644,8 +645,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -644,8 +645,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
for (i = 0; i < num_msgs; i++) { for (i = 0; i < num_msgs; i++) {
if (unlikely(msgs[i].flags & I2C_M_TEN)) { if (unlikely(msgs[i].flags & I2C_M_TEN)) {
dev_err(&dev->pdev->dev, "10 bit addressing" dev_err(&dev->pdev->dev,
"not supported\n"); "10 bit addressing not supported\n");
status = -EINVAL; status = -EINVAL;
goto out; goto out;
...@@ -789,8 +790,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) ...@@ -789,8 +790,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
if (dev->cli.count) { if (dev->cli.count) {
dev->result = -EIO; dev->result = -EIO;
dev_err(&dev->pdev->dev, "%lu bytes still remain to be" dev_err(&dev->pdev->dev,
"xfered\n", dev->cli.count); "%lu bytes still remain to be xfered\n",
dev->cli.count);
(void) init_hw(dev); (void) init_hw(dev);
} }
complete(&dev->xfer_complete); complete(&dev->xfer_complete);
...@@ -935,7 +937,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ...@@ -935,7 +937,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
} }
dev->irq = platform_get_irq(pdev, 0); dev->irq = platform_get_irq(pdev, 0);
ret = request_irq(dev->irq, i2c_irq_handler, IRQF_DISABLED, ret = request_irq(dev->irq, i2c_irq_handler, 0,
DRIVER_NAME, dev); DRIVER_NAME, dev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq); dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq);
...@@ -980,8 +982,9 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ...@@ -980,8 +982,9 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
dev_info(&pdev->dev, "initialize %s on virtual " dev_info(&pdev->dev,
"base %p\n", adap->name, dev->virtbase); "initialize %s on virtual base %p\n",
adap->name, dev->virtbase);
ret = i2c_add_numbered_adapter(adap); ret = i2c_add_numbered_adapter(adap);
if (ret) { if (ret) {
......
...@@ -610,7 +610,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev) ...@@ -610,7 +610,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
goto err_iomap; goto err_iomap;
} }
ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_DISABLED | IRQF_SHARED, ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_SHARED,
dev_name(&pdev->dev), i2c); dev_name(&pdev->dev), i2c);
if (ret != 0) { if (ret != 0) {
......
This diff is collapsed.
...@@ -306,7 +306,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev) ...@@ -306,7 +306,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
pmcmsptwi_data.irq = platform_get_irq(pldev, 0); pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
if (pmcmsptwi_data.irq) { if (pmcmsptwi_data.irq) {
rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt, rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, IRQF_SHARED | IRQF_SAMPLE_RANDOM,
pldev->name, &pmcmsptwi_data); pldev->name, &pmcmsptwi_data);
if (rc == 0) { if (rc == 0) {
/* /*
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -78,6 +80,8 @@ struct s3c24xx_i2c { ...@@ -78,6 +80,8 @@ struct s3c24xx_i2c {
struct resource *ioarea; struct resource *ioarea;
struct i2c_adapter adap; struct i2c_adapter adap;
struct s3c2410_platform_i2c *pdata;
int gpios[2];
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition; struct notifier_block freq_transition;
#endif #endif
...@@ -95,6 +99,12 @@ static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c) ...@@ -95,6 +99,12 @@ static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
struct platform_device *pdev = to_platform_device(i2c->dev); struct platform_device *pdev = to_platform_device(i2c->dev);
enum s3c24xx_i2c_type type; enum s3c24xx_i2c_type type;
#ifdef CONFIG_OF
if (i2c->dev->of_node)
return of_device_is_compatible(i2c->dev->of_node,
"samsung,s3c2440-i2c");
#endif
type = platform_get_device_id(pdev)->driver_data; type = platform_get_device_id(pdev)->driver_data;
return type == TYPE_S3C2440; return type == TYPE_S3C2440;
} }
...@@ -625,7 +635,7 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted, ...@@ -625,7 +635,7 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
{ {
struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data; struct s3c2410_platform_i2c *pdata = i2c->pdata;
unsigned long clkin = clk_get_rate(i2c->clk); unsigned long clkin = clk_get_rate(i2c->clk);
unsigned int divs, div1; unsigned int divs, div1;
unsigned long target_frequency; unsigned long target_frequency;
...@@ -741,6 +751,49 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) ...@@ -741,6 +751,49 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
} }
#endif #endif
#ifdef CONFIG_OF
static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
{
int idx, gpio, ret;
for (idx = 0; idx < 2; idx++) {
gpio = of_get_gpio(i2c->dev->of_node, idx);
if (!gpio_is_valid(gpio)) {
dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio);
goto free_gpio;
}
ret = gpio_request(gpio, "i2c-bus");
if (ret) {
dev_err(i2c->dev, "gpio [%d] request failed\n", gpio);
goto free_gpio;
}
}
return 0;
free_gpio:
while (--idx >= 0)
gpio_free(i2c->gpios[idx]);
return -EINVAL;
}
static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
{
unsigned int idx;
for (idx = 0; idx < 2; idx++)
gpio_free(i2c->gpios[idx]);
}
#else
static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
{
return -EINVAL;
}
static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
{
}
#endif
/* s3c24xx_i2c_init /* s3c24xx_i2c_init
* *
* initialise the controller, set the IO lines and frequency * initialise the controller, set the IO lines and frequency
...@@ -754,12 +807,15 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) ...@@ -754,12 +807,15 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
/* get the plafrom data */ /* get the plafrom data */
pdata = i2c->dev->platform_data; pdata = i2c->pdata;
/* inititalise the gpio */ /* inititalise the gpio */
if (pdata->cfg_gpio) if (pdata->cfg_gpio)
pdata->cfg_gpio(to_platform_device(i2c->dev)); pdata->cfg_gpio(to_platform_device(i2c->dev));
else
if (s3c24xx_i2c_parse_dt_gpio(i2c))
return -EINVAL;
/* write slave address */ /* write slave address */
...@@ -785,6 +841,34 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) ...@@ -785,6 +841,34 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
return 0; return 0;
} }
#ifdef CONFIG_OF
/* s3c24xx_i2c_parse_dt
*
* Parse the device tree node and retreive the platform data.
*/
static void
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
{
struct s3c2410_platform_i2c *pdata = i2c->pdata;
if (!np)
return;
pdata->bus_num = -1; /* i2c bus number is dynamically assigned */
of_property_read_u32(np, "samsung,i2c-sda-delay", &pdata->sda_delay);
of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr);
of_property_read_u32(np, "samsung,i2c-max-bus-freq",
(u32 *)&pdata->frequency);
}
#else
static void
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
{
return;
}
#endif
/* s3c24xx_i2c_probe /* s3c24xx_i2c_probe
* *
* called by the bus driver when a suitable device is found * called by the bus driver when a suitable device is found
...@@ -793,15 +877,17 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) ...@@ -793,15 +877,17 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_probe(struct platform_device *pdev) static int s3c24xx_i2c_probe(struct platform_device *pdev)
{ {
struct s3c24xx_i2c *i2c; struct s3c24xx_i2c *i2c;
struct s3c2410_platform_i2c *pdata; struct s3c2410_platform_i2c *pdata = NULL;
struct resource *res; struct resource *res;
int ret; int ret;
if (!pdev->dev.of_node) {
pdata = pdev->dev.platform_data; pdata = pdev->dev.platform_data;
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "no platform data\n"); dev_err(&pdev->dev, "no platform data\n");
return -EINVAL; return -EINVAL;
} }
}
i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
if (!i2c) { if (!i2c) {
...@@ -809,6 +895,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ...@@ -809,6 +895,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!i2c->pdata) {
ret = -ENOMEM;
goto err_noclk;
}
if (pdata)
memcpy(i2c->pdata, pdata, sizeof(*pdata));
else
s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE; i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &s3c24xx_i2c_algorithm; i2c->adap.algo = &s3c24xx_i2c_algorithm;
...@@ -883,7 +980,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ...@@ -883,7 +980,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto err_iomap; goto err_iomap;
} }
ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED, ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0,
dev_name(&pdev->dev), i2c); dev_name(&pdev->dev), i2c);
if (ret != 0) { if (ret != 0) {
...@@ -903,7 +1000,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ...@@ -903,7 +1000,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
* being bus 0. * being bus 0.
*/ */
i2c->adap.nr = pdata->bus_num; i2c->adap.nr = i2c->pdata->bus_num;
i2c->adap.dev.of_node = pdev->dev.of_node;
ret = i2c_add_numbered_adapter(&i2c->adap); ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) { if (ret < 0) {
...@@ -911,6 +1009,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ...@@ -911,6 +1009,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto err_cpufreq; goto err_cpufreq;
} }
of_i2c_register_devices(&i2c->adap);
platform_set_drvdata(pdev, i2c); platform_set_drvdata(pdev, i2c);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
...@@ -959,6 +1058,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) ...@@ -959,6 +1058,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
iounmap(i2c->regs); iounmap(i2c->regs);
release_resource(i2c->ioarea); release_resource(i2c->ioarea);
s3c24xx_i2c_dt_gpio_free(i2c);
kfree(i2c->ioarea); kfree(i2c->ioarea);
kfree(i2c); kfree(i2c);
...@@ -1012,6 +1112,17 @@ static struct platform_device_id s3c24xx_driver_ids[] = { ...@@ -1012,6 +1112,17 @@ static struct platform_device_id s3c24xx_driver_ids[] = {
}; };
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
#ifdef CONFIG_OF
static const struct of_device_id s3c24xx_i2c_match[] = {
{ .compatible = "samsung,s3c2410-i2c" },
{ .compatible = "samsung,s3c2440-i2c" },
{},
};
MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
#else
#define s3c24xx_i2c_match NULL
#endif
static struct platform_driver s3c24xx_i2c_driver = { static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe, .probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove, .remove = s3c24xx_i2c_remove,
...@@ -1020,6 +1131,7 @@ static struct platform_driver s3c24xx_i2c_driver = { ...@@ -1020,6 +1131,7 @@ static struct platform_driver s3c24xx_i2c_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "s3c-i2c", .name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS, .pm = S3C24XX_DEV_PM_OPS,
.of_match_table = s3c24xx_i2c_match,
}, },
}; };
......
...@@ -502,7 +502,7 @@ static int __devinit sh7760_i2c_probe(struct platform_device *pdev) ...@@ -502,7 +502,7 @@ static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
} }
OUT32(id, I2CCCR, ret); OUT32(id, I2CCCR, ret);
if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED, if (request_irq(id->irq, sh7760_i2c_irq, 0,
SH7760_I2C_DEVNAME, id)) { SH7760_I2C_DEVNAME, id)) {
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq); dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
ret = -EBUSY; ret = -EBUSY;
......
...@@ -543,7 +543,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) ...@@ -543,7 +543,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
for (n = res->start; hook && n <= res->end; n++) { for (n = res->start; hook && n <= res->end; n++) {
if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED, if (request_irq(n, sh_mobile_i2c_isr, 0,
dev_name(&dev->dev), dev)) { dev_name(&dev->dev), dev)) {
for (n--; n >= res->start; n--) for (n--; n >= res->start; n--)
free_irq(n, dev); free_irq(n, dev);
......
...@@ -916,7 +916,7 @@ stu300_probe(struct platform_device *pdev) ...@@ -916,7 +916,7 @@ stu300_probe(struct platform_device *pdev)
} }
dev->irq = platform_get_irq(pdev, 0); dev->irq = platform_get_irq(pdev, 0);
if (request_irq(dev->irq, stu300_irh, IRQF_DISABLED, if (request_irq(dev->irq, stu300_irh, 0,
NAME, dev)) { NAME, dev)) {
ret = -EIO; ret = -EIO;
goto err_no_irq; goto err_no_irq;
......
...@@ -566,7 +566,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) ...@@ -566,7 +566,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
struct clk *clk; struct clk *clk;
struct clk *i2c_clk; struct clk *i2c_clk;
const unsigned int *prop; const unsigned int *prop;
void *base; void __iomem *base;
int irq; int irq;
int ret = 0; int ret = 0;
......
...@@ -32,10 +32,9 @@ ...@@ -32,10 +32,9 @@
struct omap_i2c_bus_platform_data { struct omap_i2c_bus_platform_data {
u32 clkrate; u32 clkrate;
u32 rev;
u32 flags;
void (*set_mpu_wkup_lat)(struct device *dev, long set); void (*set_mpu_wkup_lat)(struct device *dev, long set);
int (*device_enable) (struct platform_device *pdev);
int (*device_shutdown) (struct platform_device *pdev);
int (*device_idle) (struct platform_device *pdev);
}; };
#endif #endif
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