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 ...
This commit is contained in:
commit
b4beb4bf99
26 changed files with 1551 additions and 692 deletions
25
Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt
Normal file
25
Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
* 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>;
|
||||
};
|
39
Documentation/devicetree/bindings/i2c/samsung-i2c.txt
Normal file
39
Documentation/devicetree/bindings/i2c/samsung-i2c.txt
Normal file
|
@ -0,0 +1,39 @@
|
|||
* 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 @@
|
|||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
**/
|
||||
struct imxi2c_platform_data {
|
||||
int (*init)(struct device *dev);
|
||||
void (*exit)(struct device *dev);
|
||||
int bitrate;
|
||||
};
|
||||
|
||||
|
|
|
@ -108,6 +108,22 @@ static inline int omap1_i2c_add_bus(int bus_id)
|
|||
res[1].start = INT_I2C;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -138,6 +154,7 @@ static inline int omap2_i2c_add_bus(int bus_id)
|
|||
struct omap_device *od;
|
||||
char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN];
|
||||
struct omap_i2c_bus_platform_data *pdata;
|
||||
struct omap_i2c_dev_attr *dev_attr;
|
||||
|
||||
omap2_i2c_mux_pins(bus_id);
|
||||
|
||||
|
@ -151,6 +168,16 @@ static inline int omap2_i2c_add_bus(int bus_id)
|
|||
}
|
||||
|
||||
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
|
||||
* set a wake up latency constraint for the MPU. This is to
|
||||
|
|
|
@ -394,19 +394,6 @@ typedef struct psc_spi {
|
|||
#define PSC_SPITXRX_LC (1 << 29)
|
||||
#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. */
|
||||
#define PSC_SMBCFG_RT_MASK (3 << 30)
|
||||
#define PSC_SMBCFG_RT_FIFO1 (0 << 30)
|
||||
|
|
|
@ -350,15 +350,25 @@ config I2C_DAVINCI
|
|||
devices such as DaVinci NIC.
|
||||
For details please see http://www.ti.com/davinci
|
||||
|
||||
config I2C_DESIGNWARE
|
||||
tristate "Synopsys DesignWare"
|
||||
config I2C_DESIGNWARE_PLATFORM
|
||||
tristate "Synopsys DesignWare Platfrom"
|
||||
depends on HAVE_CLK
|
||||
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.
|
||||
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
|
||||
tristate "GPIO-based bitbanging I2C"
|
||||
|
|
|
@ -33,7 +33,10 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
|
|||
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
|
||||
obj-$(CONFIG_I2C_CPM) += i2c-cpm.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_HIGHLANDER) += i2c-highlander.o
|
||||
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
|
||||
|
|
|
@ -39,29 +39,41 @@
|
|||
#include <asm/mach-au1x00/au1xxx.h>
|
||||
#include <asm/mach-au1x00/au1xxx_psc.h>
|
||||
|
||||
#define PSC_SEL 0x00
|
||||
#define PSC_CTRL 0x04
|
||||
#define PSC_SMBCFG 0x08
|
||||
#define PSC_SMBMSK 0x0C
|
||||
#define PSC_SMBPCR 0x10
|
||||
#define PSC_SMBSTAT 0x14
|
||||
#define PSC_SMBEVNT 0x18
|
||||
#define PSC_SMBTXRX 0x1C
|
||||
#define PSC_SMBTMR 0x20
|
||||
|
||||
struct i2c_au1550_data {
|
||||
u32 psc_base;
|
||||
void __iomem *psc_base;
|
||||
int xfer_timeout;
|
||||
int ack_timeout;
|
||||
struct i2c_adapter adap;
|
||||
struct resource *ioarea;
|
||||
};
|
||||
|
||||
static int
|
||||
wait_xfer_done(struct i2c_au1550_data *adap)
|
||||
static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v)
|
||||
{
|
||||
u32 stat;
|
||||
int i;
|
||||
volatile psc_smb_t *sp;
|
||||
__raw_writel(v, a->psc_base + r);
|
||||
wmb();
|
||||
}
|
||||
|
||||
sp = (volatile psc_smb_t *)(adap->psc_base);
|
||||
static inline unsigned long RD(struct i2c_au1550_data *a, int r)
|
||||
{
|
||||
return __raw_readl(a->psc_base + r);
|
||||
}
|
||||
|
||||
/* Wait for Tx Buffer Empty
|
||||
*/
|
||||
static int wait_xfer_done(struct i2c_au1550_data *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Wait for Tx Buffer Empty */
|
||||
for (i = 0; i < adap->xfer_timeout; i++) {
|
||||
stat = sp->psc_smbstat;
|
||||
au_sync();
|
||||
if ((stat & PSC_SMBSTAT_TE) != 0)
|
||||
if (RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_TE)
|
||||
return 0;
|
||||
|
||||
udelay(1);
|
||||
|
@ -70,41 +82,27 @@ wait_xfer_done(struct i2c_au1550_data *adap)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int
|
||||
wait_ack(struct i2c_au1550_data *adap)
|
||||
static int wait_ack(struct i2c_au1550_data *adap)
|
||||
{
|
||||
u32 stat;
|
||||
volatile psc_smb_t *sp;
|
||||
unsigned long stat;
|
||||
|
||||
if (wait_xfer_done(adap))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
sp = (volatile psc_smb_t *)(adap->psc_base);
|
||||
|
||||
stat = sp->psc_smbevnt;
|
||||
au_sync();
|
||||
|
||||
stat = RD(adap, PSC_SMBEVNT);
|
||||
if ((stat & (PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | PSC_SMBEVNT_AL)) != 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wait_master_done(struct i2c_au1550_data *adap)
|
||||
static int wait_master_done(struct i2c_au1550_data *adap)
|
||||
{
|
||||
u32 stat;
|
||||
int i;
|
||||
volatile psc_smb_t *sp;
|
||||
int i;
|
||||
|
||||
sp = (volatile psc_smb_t *)(adap->psc_base);
|
||||
|
||||
/* Wait for Master Done.
|
||||
*/
|
||||
for (i = 0; i < adap->xfer_timeout; i++) {
|
||||
stat = sp->psc_smbevnt;
|
||||
au_sync();
|
||||
if ((stat & PSC_SMBEVNT_MD) != 0)
|
||||
/* Wait for Master Done. */
|
||||
for (i = 0; i < 2 * adap->xfer_timeout; i++) {
|
||||
if ((RD(adap, PSC_SMBEVNT) & PSC_SMBEVNT_MD) != 0)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
@ -115,29 +113,20 @@ wait_master_done(struct i2c_au1550_data *adap)
|
|||
static int
|
||||
do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
|
||||
{
|
||||
volatile psc_smb_t *sp;
|
||||
u32 stat;
|
||||
unsigned long stat;
|
||||
|
||||
sp = (volatile psc_smb_t *)(adap->psc_base);
|
||||
|
||||
/* Reset the FIFOs, clear events.
|
||||
*/
|
||||
stat = sp->psc_smbstat;
|
||||
sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
|
||||
au_sync();
|
||||
/* Reset the FIFOs, clear events. */
|
||||
stat = RD(adap, PSC_SMBSTAT);
|
||||
WR(adap, PSC_SMBEVNT, PSC_SMBEVNT_ALLCLR);
|
||||
|
||||
if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
|
||||
sp->psc_smbpcr = PSC_SMBPCR_DC;
|
||||
au_sync();
|
||||
do {
|
||||
stat = sp->psc_smbpcr;
|
||||
au_sync();
|
||||
} while ((stat & PSC_SMBPCR_DC) != 0);
|
||||
WR(adap, PSC_SMBPCR, PSC_SMBPCR_DC);
|
||||
while ((RD(adap, PSC_SMBPCR) & PSC_SMBPCR_DC) != 0)
|
||||
cpu_relax();
|
||||
udelay(50);
|
||||
}
|
||||
|
||||
/* Write out the i2c chip address and specify operation
|
||||
*/
|
||||
/* Write out the i2c chip address and specify operation */
|
||||
addr <<= 1;
|
||||
if (rd)
|
||||
addr |= 1;
|
||||
|
@ -146,56 +135,42 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
|
|||
if (q)
|
||||
addr |= PSC_SMBTXRX_STP;
|
||||
|
||||
/* Put byte into fifo, start up master.
|
||||
*/
|
||||
sp->psc_smbtxrx = addr;
|
||||
au_sync();
|
||||
sp->psc_smbpcr = PSC_SMBPCR_MS;
|
||||
au_sync();
|
||||
/* Put byte into fifo, start up master. */
|
||||
WR(adap, PSC_SMBTXRX, addr);
|
||||
WR(adap, PSC_SMBPCR, PSC_SMBPCR_MS);
|
||||
if (wait_ack(adap))
|
||||
return -EIO;
|
||||
return (q) ? wait_master_done(adap) : 0;
|
||||
}
|
||||
|
||||
static u32
|
||||
wait_for_rx_byte(struct i2c_au1550_data *adap, u32 *ret_data)
|
||||
static int wait_for_rx_byte(struct i2c_au1550_data *adap, unsigned char *out)
|
||||
{
|
||||
int j;
|
||||
u32 data, stat;
|
||||
volatile psc_smb_t *sp;
|
||||
int j;
|
||||
|
||||
if (wait_xfer_done(adap))
|
||||
return -EIO;
|
||||
|
||||
sp = (volatile psc_smb_t *)(adap->psc_base);
|
||||
|
||||
j = adap->xfer_timeout * 100;
|
||||
do {
|
||||
j--;
|
||||
if (j <= 0)
|
||||
return -EIO;
|
||||
|
||||
stat = sp->psc_smbstat;
|
||||
au_sync();
|
||||
if ((stat & PSC_SMBSTAT_RE) == 0)
|
||||
if ((RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_RE) == 0)
|
||||
j = 0;
|
||||
else
|
||||
udelay(1);
|
||||
} while (j > 0);
|
||||
data = sp->psc_smbtxrx;
|
||||
au_sync();
|
||||
*ret_data = data;
|
||||
|
||||
*out = RD(adap, PSC_SMBTXRX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
|
||||
static int i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
int i;
|
||||
u32 data;
|
||||
volatile psc_smb_t *sp;
|
||||
int i;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
@ -204,62 +179,46 @@ i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
|
|||
* zero bytes for timing, waiting for bytes to appear in the
|
||||
* receive fifo, then reading the bytes.
|
||||
*/
|
||||
|
||||
sp = (volatile psc_smb_t *)(adap->psc_base);
|
||||
|
||||
i = 0;
|
||||
while (i < (len-1)) {
|
||||
sp->psc_smbtxrx = 0;
|
||||
au_sync();
|
||||
if (wait_for_rx_byte(adap, &data))
|
||||
while (i < (len - 1)) {
|
||||
WR(adap, PSC_SMBTXRX, 0);
|
||||
if (wait_for_rx_byte(adap, &buf[i]))
|
||||
return -EIO;
|
||||
|
||||
buf[i] = data;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* The last byte has to indicate transfer done.
|
||||
*/
|
||||
sp->psc_smbtxrx = PSC_SMBTXRX_STP;
|
||||
au_sync();
|
||||
/* The last byte has to indicate transfer done. */
|
||||
WR(adap, PSC_SMBTXRX, PSC_SMBTXRX_STP);
|
||||
if (wait_master_done(adap))
|
||||
return -EIO;
|
||||
|
||||
data = sp->psc_smbtxrx;
|
||||
au_sync();
|
||||
buf[i] = data;
|
||||
buf[i] = (unsigned char)(RD(adap, PSC_SMBTXRX) & 0xff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i2c_write(struct i2c_au1550_data *adap, unsigned char *buf,
|
||||
static int i2c_write(struct i2c_au1550_data *adap, unsigned char *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
int i;
|
||||
u32 data;
|
||||
volatile psc_smb_t *sp;
|
||||
int i;
|
||||
unsigned long data;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
sp = (volatile psc_smb_t *)(adap->psc_base);
|
||||
|
||||
i = 0;
|
||||
while (i < (len-1)) {
|
||||
data = buf[i];
|
||||
sp->psc_smbtxrx = data;
|
||||
au_sync();
|
||||
WR(adap, PSC_SMBTXRX, data);
|
||||
if (wait_ack(adap))
|
||||
return -EIO;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* The last byte has to indicate transfer done.
|
||||
*/
|
||||
/* The last byte has to indicate transfer done. */
|
||||
data = buf[i];
|
||||
data |= PSC_SMBTXRX_STP;
|
||||
sp->psc_smbtxrx = data;
|
||||
au_sync();
|
||||
WR(adap, PSC_SMBTXRX, data);
|
||||
if (wait_master_done(adap))
|
||||
return -EIO;
|
||||
return 0;
|
||||
|
@ -269,12 +228,10 @@ static int
|
|||
au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct i2c_au1550_data *adap = i2c_adap->algo_data;
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)adap->psc_base;
|
||||
struct i2c_msg *p;
|
||||
int i, err = 0;
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_ENABLE;
|
||||
au_sync();
|
||||
WR(adap, PSC_CTRL, PSC_CTRL_ENABLE);
|
||||
|
||||
for (i = 0; !err && i < num; i++) {
|
||||
p = &msgs[i];
|
||||
|
@ -293,14 +250,12 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
|
|||
if (err == 0)
|
||||
err = num;
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_SUSPEND;
|
||||
au_sync();
|
||||
WR(adap, PSC_CTRL, PSC_CTRL_SUSPEND);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static u32
|
||||
au1550_func(struct i2c_adapter *adap)
|
||||
static u32 au1550_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
@ -312,57 +267,45 @@ static const struct i2c_algorithm au1550_algo = {
|
|||
|
||||
static void i2c_au1550_setup(struct i2c_au1550_data *priv)
|
||||
{
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
u32 stat;
|
||||
unsigned long cfg;
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_DISABLE;
|
||||
au_sync();
|
||||
sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
|
||||
sp->psc_smbcfg = 0;
|
||||
au_sync();
|
||||
sp->psc_ctrl = PSC_CTRL_ENABLE;
|
||||
au_sync();
|
||||
do {
|
||||
stat = sp->psc_smbstat;
|
||||
au_sync();
|
||||
} while ((stat & PSC_SMBSTAT_SR) == 0);
|
||||
WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
|
||||
WR(priv, PSC_SEL, PSC_SEL_PS_SMBUSMODE);
|
||||
WR(priv, PSC_SMBCFG, 0);
|
||||
WR(priv, PSC_CTRL, PSC_CTRL_ENABLE);
|
||||
while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
|
||||
cpu_relax();
|
||||
|
||||
sp->psc_smbcfg = (PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 |
|
||||
PSC_SMBCFG_DD_DISABLE);
|
||||
cfg = PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | PSC_SMBCFG_DD_DISABLE;
|
||||
WR(priv, PSC_SMBCFG, cfg);
|
||||
|
||||
/* Divide by 8 to get a 6.25 MHz clock. The later protocol
|
||||
* timings are based on this clock.
|
||||
*/
|
||||
sp->psc_smbcfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8);
|
||||
sp->psc_smbmsk = PSC_SMBMSK_ALLMASK;
|
||||
au_sync();
|
||||
cfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8);
|
||||
WR(priv, PSC_SMBCFG, cfg);
|
||||
WR(priv, PSC_SMBMSK, PSC_SMBMSK_ALLMASK);
|
||||
|
||||
/* Set the protocol timer values. See Table 71 in the
|
||||
* Au1550 Data Book for standard timing values.
|
||||
*/
|
||||
sp->psc_smbtmr = PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
|
||||
WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
|
||||
PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
|
||||
PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
|
||||
PSC_SMBTMR_SET_CH(15);
|
||||
au_sync();
|
||||
PSC_SMBTMR_SET_CH(15));
|
||||
|
||||
sp->psc_smbcfg |= PSC_SMBCFG_DE_ENABLE;
|
||||
do {
|
||||
stat = sp->psc_smbstat;
|
||||
au_sync();
|
||||
} while ((stat & PSC_SMBSTAT_SR) == 0);
|
||||
cfg |= PSC_SMBCFG_DE_ENABLE;
|
||||
WR(priv, PSC_SMBCFG, cfg);
|
||||
while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
|
||||
cpu_relax();
|
||||
|
||||
sp->psc_ctrl = PSC_CTRL_SUSPEND;
|
||||
au_sync();
|
||||
WR(priv, PSC_CTRL, PSC_CTRL_SUSPEND);
|
||||
}
|
||||
|
||||
static void i2c_au1550_disable(struct i2c_au1550_data *priv)
|
||||
{
|
||||
volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
|
||||
|
||||
sp->psc_smbcfg = 0;
|
||||
sp->psc_ctrl = PSC_CTRL_DISABLE;
|
||||
au_sync();
|
||||
WR(priv, PSC_SMBCFG, 0);
|
||||
WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -396,9 +339,12 @@ i2c_au1550_probe(struct platform_device *pdev)
|
|||
goto out_mem;
|
||||
}
|
||||
|
||||
priv->psc_base = CKSEG1ADDR(r->start);
|
||||
priv->psc_base = ioremap(r->start, resource_size(r));
|
||||
if (!priv->psc_base) {
|
||||
ret = -EIO;
|
||||
goto out_map;
|
||||
}
|
||||
priv->xfer_timeout = 200;
|
||||
priv->ack_timeout = 200;
|
||||
|
||||
priv->adap.nr = pdev->id;
|
||||
priv->adap.algo = &au1550_algo;
|
||||
|
@ -406,8 +352,7 @@ i2c_au1550_probe(struct platform_device *pdev)
|
|||
priv->adap.dev.parent = &pdev->dev;
|
||||
strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
|
||||
|
||||
/* Now, set up the PSC for SMBus PIO mode.
|
||||
*/
|
||||
/* Now, set up the PSC for SMBus PIO mode. */
|
||||
i2c_au1550_setup(priv);
|
||||
|
||||
ret = i2c_add_numbered_adapter(&priv->adap);
|
||||
|
@ -417,7 +362,8 @@ i2c_au1550_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
i2c_au1550_disable(priv);
|
||||
|
||||
iounmap(priv->psc_base);
|
||||
out_map:
|
||||
release_resource(priv->ioarea);
|
||||
kfree(priv->ioarea);
|
||||
out_mem:
|
||||
|
@ -426,14 +372,14 @@ i2c_au1550_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit
|
||||
i2c_au1550_remove(struct platform_device *pdev)
|
||||
static int __devexit i2c_au1550_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
i2c_del_adapter(&priv->adap);
|
||||
i2c_au1550_disable(priv);
|
||||
iounmap(priv->psc_base);
|
||||
release_resource(priv->ioarea);
|
||||
kfree(priv->ioarea);
|
||||
kfree(priv);
|
||||
|
@ -441,49 +387,51 @@ i2c_au1550_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int
|
||||
i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int i2c_au1550_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
|
||||
struct i2c_au1550_data *priv = dev_get_drvdata(dev);
|
||||
|
||||
i2c_au1550_disable(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i2c_au1550_resume(struct platform_device *pdev)
|
||||
static int i2c_au1550_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
|
||||
struct i2c_au1550_data *priv = dev_get_drvdata(dev);
|
||||
|
||||
i2c_au1550_setup(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops i2c_au1550_pmops = {
|
||||
.suspend = i2c_au1550_suspend,
|
||||
.resume = i2c_au1550_resume,
|
||||
};
|
||||
|
||||
#define AU1XPSC_SMBUS_PMOPS (&i2c_au1550_pmops)
|
||||
|
||||
#else
|
||||
#define i2c_au1550_suspend NULL
|
||||
#define i2c_au1550_resume NULL
|
||||
#define AU1XPSC_SMBUS_PMOPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver au1xpsc_smbus_driver = {
|
||||
.driver = {
|
||||
.name = "au1xpsc_smbus",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = AU1XPSC_SMBUS_PMOPS,
|
||||
},
|
||||
.probe = i2c_au1550_probe,
|
||||
.remove = __devexit_p(i2c_au1550_remove),
|
||||
.suspend = i2c_au1550_suspend,
|
||||
.resume = i2c_au1550_resume,
|
||||
};
|
||||
|
||||
static int __init
|
||||
i2c_au1550_init(void)
|
||||
static int __init i2c_au1550_init(void)
|
||||
{
|
||||
return platform_driver_register(&au1xpsc_smbus_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
i2c_au1550_exit(void)
|
||||
static void __exit i2c_au1550_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&au1xpsc_smbus_driver);
|
||||
}
|
||||
|
|
|
@ -631,7 +631,7 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev)
|
|||
struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
|
||||
|
||||
int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
|
||||
IRQF_DISABLED, pdev->name, iface);
|
||||
0, pdev->name, iface);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
|
||||
return -ENODEV;
|
||||
|
@ -702,7 +702,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
|
||||
IRQF_DISABLED, pdev->name, iface);
|
||||
0, pdev->name, iface);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
|
||||
rc = -ENODEV;
|
||||
|
|
|
@ -25,18 +25,15 @@
|
|||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
#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/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/delay.h>
|
||||
#include "i2c-designware-core.h"
|
||||
|
||||
/*
|
||||
* Registers offset
|
||||
|
@ -68,15 +65,10 @@
|
|||
#define DW_IC_STATUS 0x70
|
||||
#define DW_IC_TXFLR 0x74
|
||||
#define DW_IC_RXFLR 0x78
|
||||
#define DW_IC_COMP_PARAM_1 0xf4
|
||||
#define DW_IC_TX_ABRT_SOURCE 0x80
|
||||
|
||||
#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
|
||||
#define DW_IC_COMP_PARAM_1 0xf4
|
||||
#define DW_IC_COMP_TYPE 0xfc
|
||||
#define DW_IC_COMP_TYPE_VALUE 0x44570140
|
||||
|
||||
#define DW_IC_INTR_RX_UNDER 0x001
|
||||
#define DW_IC_INTR_RX_OVER 0x002
|
||||
|
@ -170,55 +162,23 @@ static char *abort_sources[] = {
|
|||
"lost arbitration",
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 transferred
|
||||
* @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;
|
||||
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;
|
||||
struct i2c_adapter adapter;
|
||||
unsigned int tx_fifo_depth;
|
||||
unsigned int rx_fifo_depth;
|
||||
};
|
||||
u32 dw_readl(struct dw_i2c_dev *dev, int offset)
|
||||
{
|
||||
u32 value = readl(dev->base + offset);
|
||||
|
||||
if (dev->swab)
|
||||
return swab32(value);
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
|
||||
{
|
||||
if (dev->swab)
|
||||
b = swab32(b);
|
||||
|
||||
writel(b, dev->base + offset);
|
||||
}
|
||||
|
||||
static u32
|
||||
i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
|
||||
|
@ -283,13 +243,29 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
|
|||
* This function is called during I2C init function, and in case of timeout at
|
||||
* run time.
|
||||
*/
|
||||
static void i2c_dw_init(struct dw_i2c_dev *dev)
|
||||
int i2c_dw_init(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 input_clock_khz = clk_get_rate(dev->clk) / 1000;
|
||||
u32 ic_con, hcnt, lcnt;
|
||||
u32 input_clock_khz;
|
||||
u32 hcnt, lcnt;
|
||||
u32 reg;
|
||||
|
||||
input_clock_khz = dev->get_clk_rate_khz(dev);
|
||||
|
||||
/* Configure register endianess access */
|
||||
reg = dw_readl(dev, DW_IC_COMP_TYPE);
|
||||
if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
|
||||
dev->swab = 1;
|
||||
reg = DW_IC_COMP_TYPE_VALUE;
|
||||
}
|
||||
|
||||
if (reg != DW_IC_COMP_TYPE_VALUE) {
|
||||
dev_err(dev->dev, "Unknown Synopsys component type: "
|
||||
"0x%08x\n", reg);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Disable the adapter */
|
||||
writel(0, dev->base + DW_IC_ENABLE);
|
||||
dw_writel(dev, 0, DW_IC_ENABLE);
|
||||
|
||||
/* set standard and fast speed deviders for high/low periods */
|
||||
|
||||
|
@ -303,8 +279,8 @@ static void i2c_dw_init(struct dw_i2c_dev *dev)
|
|||
47, /* tLOW = 4.7 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0); /* No offset */
|
||||
writel(hcnt, dev->base + DW_IC_SS_SCL_HCNT);
|
||||
writel(lcnt, dev->base + DW_IC_SS_SCL_LCNT);
|
||||
dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
|
||||
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
|
||||
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
|
||||
|
||||
/* Fast-mode */
|
||||
|
@ -317,18 +293,17 @@ static void i2c_dw_init(struct dw_i2c_dev *dev)
|
|||
13, /* tLOW = 1.3 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0); /* No offset */
|
||||
writel(hcnt, dev->base + DW_IC_FS_SCL_HCNT);
|
||||
writel(lcnt, dev->base + DW_IC_FS_SCL_LCNT);
|
||||
dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
|
||||
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
|
||||
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
|
||||
|
||||
/* Configure Tx/Rx FIFO threshold levels */
|
||||
writel(dev->tx_fifo_depth - 1, dev->base + DW_IC_TX_TL);
|
||||
writel(0, dev->base + DW_IC_RX_TL);
|
||||
dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
|
||||
dw_writel(dev, 0, DW_IC_RX_TL);
|
||||
|
||||
/* configure the i2c master */
|
||||
ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
|
||||
DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
|
||||
writel(ic_con, dev->base + DW_IC_CON);
|
||||
dw_writel(dev, dev->master_cfg , DW_IC_CON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -338,7 +313,7 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
|
|||
{
|
||||
int timeout = TIMEOUT;
|
||||
|
||||
while (readl(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
|
||||
while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
|
||||
if (timeout <= 0) {
|
||||
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
||||
return -ETIMEDOUT;
|
||||
|
@ -356,24 +331,24 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
|||
u32 ic_con;
|
||||
|
||||
/* Disable the adapter */
|
||||
writel(0, dev->base + DW_IC_ENABLE);
|
||||
dw_writel(dev, 0, DW_IC_ENABLE);
|
||||
|
||||
/* set the slave (target) address */
|
||||
writel(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR);
|
||||
dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR);
|
||||
|
||||
/* if the slave address is ten bit address, enable 10BITADDR */
|
||||
ic_con = readl(dev->base + DW_IC_CON);
|
||||
ic_con = dw_readl(dev, DW_IC_CON);
|
||||
if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
|
||||
ic_con |= DW_IC_CON_10BITADDR_MASTER;
|
||||
else
|
||||
ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
|
||||
writel(ic_con, dev->base + DW_IC_CON);
|
||||
dw_writel(dev, ic_con, DW_IC_CON);
|
||||
|
||||
/* Enable the adapter */
|
||||
writel(1, dev->base + DW_IC_ENABLE);
|
||||
dw_writel(dev, 1, DW_IC_ENABLE);
|
||||
|
||||
/* Enable interrupts */
|
||||
writel(DW_IC_INTR_DEFAULT_MASK, dev->base + DW_IC_INTR_MASK);
|
||||
dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -382,7 +357,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
|||
* messages into the tx buffer. Even if the size of i2c_msg data is
|
||||
* longer than the size of the tx buffer, it handles everything.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_msg *msgs = dev->msgs;
|
||||
|
@ -420,15 +395,15 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|||
buf_len = msgs[dev->msg_write_idx].len;
|
||||
}
|
||||
|
||||
tx_limit = dev->tx_fifo_depth - readl(dev->base + DW_IC_TXFLR);
|
||||
rx_limit = dev->rx_fifo_depth - readl(dev->base + DW_IC_RXFLR);
|
||||
tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
|
||||
rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
|
||||
|
||||
while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
|
||||
if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
|
||||
writel(0x100, dev->base + DW_IC_DATA_CMD);
|
||||
dw_writel(dev, 0x100, DW_IC_DATA_CMD);
|
||||
rx_limit--;
|
||||
} else
|
||||
writel(*buf++, dev->base + DW_IC_DATA_CMD);
|
||||
dw_writel(dev, *buf++, DW_IC_DATA_CMD);
|
||||
tx_limit--; buf_len--;
|
||||
}
|
||||
|
||||
|
@ -453,7 +428,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|||
if (dev->msg_err)
|
||||
intr_mask = 0;
|
||||
|
||||
writel(intr_mask, dev->base + DW_IC_INTR_MASK);
|
||||
dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -477,10 +452,10 @@ i2c_dw_read(struct dw_i2c_dev *dev)
|
|||
buf = dev->rx_buf;
|
||||
}
|
||||
|
||||
rx_valid = readl(dev->base + DW_IC_RXFLR);
|
||||
rx_valid = dw_readl(dev, DW_IC_RXFLR);
|
||||
|
||||
for (; len > 0 && rx_valid > 0; len--, rx_valid--)
|
||||
*buf++ = readl(dev->base + DW_IC_DATA_CMD);
|
||||
*buf++ = dw_readl(dev, DW_IC_DATA_CMD);
|
||||
|
||||
if (len > 0) {
|
||||
dev->status |= STATUS_READ_IN_PROGRESS;
|
||||
|
@ -518,7 +493,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
|
|||
/*
|
||||
* Prepare controller for a transaction and call i2c_dw_xfer_msg
|
||||
*/
|
||||
static int
|
||||
int
|
||||
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
|
@ -527,6 +502,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
|
||||
INIT_COMPLETION(dev->cmd_complete);
|
||||
dev->msgs = msgs;
|
||||
|
@ -563,7 +539,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
/* no error */
|
||||
if (likely(!dev->cmd_err)) {
|
||||
/* Disable the adapter */
|
||||
writel(0, dev->base + DW_IC_ENABLE);
|
||||
dw_writel(dev, 0, DW_IC_ENABLE);
|
||||
ret = num;
|
||||
goto done;
|
||||
}
|
||||
|
@ -576,19 +552,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
ret = -EIO;
|
||||
|
||||
done:
|
||||
pm_runtime_put(dev->dev);
|
||||
mutex_unlock(&dev->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 i2c_dw_func(struct i2c_adapter *adap)
|
||||
u32 i2c_dw_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return 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;
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
return dev->functionality;
|
||||
}
|
||||
|
||||
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
|
||||
|
@ -601,47 +574,47 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
|
|||
* in the IC_RAW_INTR_STAT register.
|
||||
*
|
||||
* That is,
|
||||
* stat = readl(IC_INTR_STAT);
|
||||
* stat = dw_readl(IC_INTR_STAT);
|
||||
* equals to,
|
||||
* stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
|
||||
* stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
|
||||
*
|
||||
* The raw version might be useful for debugging purposes.
|
||||
*/
|
||||
stat = readl(dev->base + DW_IC_INTR_STAT);
|
||||
stat = dw_readl(dev, DW_IC_INTR_STAT);
|
||||
|
||||
/*
|
||||
* Do not use the IC_CLR_INTR register to clear interrupts, or
|
||||
* you'll miss some interrupts, triggered during the period from
|
||||
* readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
|
||||
* dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
|
||||
*
|
||||
* Instead, use the separately-prepared IC_CLR_* registers.
|
||||
*/
|
||||
if (stat & DW_IC_INTR_RX_UNDER)
|
||||
readl(dev->base + DW_IC_CLR_RX_UNDER);
|
||||
dw_readl(dev, DW_IC_CLR_RX_UNDER);
|
||||
if (stat & DW_IC_INTR_RX_OVER)
|
||||
readl(dev->base + DW_IC_CLR_RX_OVER);
|
||||
dw_readl(dev, DW_IC_CLR_RX_OVER);
|
||||
if (stat & DW_IC_INTR_TX_OVER)
|
||||
readl(dev->base + DW_IC_CLR_TX_OVER);
|
||||
dw_readl(dev, DW_IC_CLR_TX_OVER);
|
||||
if (stat & DW_IC_INTR_RD_REQ)
|
||||
readl(dev->base + DW_IC_CLR_RD_REQ);
|
||||
dw_readl(dev, DW_IC_CLR_RD_REQ);
|
||||
if (stat & DW_IC_INTR_TX_ABRT) {
|
||||
/*
|
||||
* The IC_TX_ABRT_SOURCE register is cleared whenever
|
||||
* the IC_CLR_TX_ABRT is read. Preserve it beforehand.
|
||||
*/
|
||||
dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE);
|
||||
readl(dev->base + DW_IC_CLR_TX_ABRT);
|
||||
dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
|
||||
dw_readl(dev, DW_IC_CLR_TX_ABRT);
|
||||
}
|
||||
if (stat & DW_IC_INTR_RX_DONE)
|
||||
readl(dev->base + DW_IC_CLR_RX_DONE);
|
||||
dw_readl(dev, DW_IC_CLR_RX_DONE);
|
||||
if (stat & DW_IC_INTR_ACTIVITY)
|
||||
readl(dev->base + DW_IC_CLR_ACTIVITY);
|
||||
dw_readl(dev, DW_IC_CLR_ACTIVITY);
|
||||
if (stat & DW_IC_INTR_STOP_DET)
|
||||
readl(dev->base + DW_IC_CLR_STOP_DET);
|
||||
dw_readl(dev, DW_IC_CLR_STOP_DET);
|
||||
if (stat & DW_IC_INTR_START_DET)
|
||||
readl(dev->base + DW_IC_CLR_START_DET);
|
||||
dw_readl(dev, DW_IC_CLR_START_DET);
|
||||
if (stat & DW_IC_INTR_GEN_CALL)
|
||||
readl(dev->base + DW_IC_CLR_GEN_CALL);
|
||||
dw_readl(dev, DW_IC_CLR_GEN_CALL);
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
@ -650,13 +623,19 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
|
|||
* Interrupt service routine. This gets called whenever an I2C interrupt
|
||||
* occurs.
|
||||
*/
|
||||
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
||||
irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
||||
{
|
||||
struct dw_i2c_dev *dev = dev_id;
|
||||
u32 stat;
|
||||
u32 stat, enabled;
|
||||
|
||||
enabled = dw_readl(dev, DW_IC_ENABLE);
|
||||
stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
|
||||
dev_dbg(dev->dev, "%s: %s enabled= 0x%x stat=0x%x\n", __func__,
|
||||
dev->adapter.name, enabled, stat);
|
||||
if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
|
||||
return IRQ_NONE;
|
||||
|
||||
stat = i2c_dw_read_clear_intrbits(dev);
|
||||
dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
|
||||
|
||||
if (stat & DW_IC_INTR_TX_ABRT) {
|
||||
dev->cmd_err |= DW_IC_ERR_TX_ABRT;
|
||||
|
@ -666,7 +645,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
|||
* Anytime TX_ABRT is set, the contents of the tx/rx
|
||||
* buffers are flushed. Make sure to skip them.
|
||||
*/
|
||||
writel(0, dev->base + DW_IC_INTR_MASK);
|
||||
dw_writel(dev, 0, DW_IC_INTR_MASK);
|
||||
goto tx_aborted;
|
||||
}
|
||||
|
||||
|
@ -689,159 +668,38 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm i2c_dw_algo = {
|
||||
.master_xfer = i2c_dw_xfer,
|
||||
.functionality = i2c_dw_func,
|
||||
};
|
||||
|
||||
static int __devinit dw_i2c_probe(struct platform_device *pdev)
|
||||
void i2c_dw_enable(struct dw_i2c_dev *dev)
|
||||
{
|
||||
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);
|
||||
if (IS_ERR(dev->clk)) {
|
||||
r = -ENODEV;
|
||||
goto err_free_mem;
|
||||
}
|
||||
clk_enable(dev->clk);
|
||||
|
||||
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 = readl(dev->base + DW_IC_COMP_PARAM_1);
|
||||
|
||||
dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
|
||||
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
|
||||
}
|
||||
i2c_dw_init(dev);
|
||||
|
||||
writel(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */
|
||||
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;
|
||||
/* Enable the adapter */
|
||||
dw_writel(dev, 1, DW_IC_ENABLE);
|
||||
}
|
||||
|
||||
static int __devexit dw_i2c_remove(struct platform_device *pdev)
|
||||
u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
|
||||
{
|
||||
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;
|
||||
|
||||
writel(0, dev->base + DW_IC_ENABLE);
|
||||
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;
|
||||
return dw_readl(dev, DW_IC_ENABLE);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
void i2c_dw_disable(struct dw_i2c_dev *dev)
|
||||
{
|
||||
return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
|
||||
}
|
||||
module_init(dw_i2c_init_driver);
|
||||
/* Disable controller */
|
||||
dw_writel(dev, 0, DW_IC_ENABLE);
|
||||
|
||||
static void __exit dw_i2c_exit_driver(void)
|
||||
/* Disable all interupts */
|
||||
dw_writel(dev, 0, DW_IC_INTR_MASK);
|
||||
dw_readl(dev, DW_IC_CLR_INTR);
|
||||
}
|
||||
|
||||
void i2c_dw_clear_int(struct dw_i2c_dev *dev)
|
||||
{
|
||||
platform_driver_unregister(&dw_i2c_driver);
|
||||
dw_readl(dev, DW_IC_CLR_INTR);
|
||||
}
|
||||
module_exit(dw_i2c_exit_driver);
|
||||
|
||||
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
|
||||
MODULE_LICENSE("GPL");
|
||||
void i2c_dw_disable_int(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dw_writel(dev, 0, DW_IC_INTR_MASK);
|
||||
}
|
||||
|
||||
u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
|
||||
{
|
||||
return dw_readl(dev, DW_IC_COMP_PARAM_1);
|
||||
}
|
105
drivers/i2c/busses/i2c-designware-core.h
Normal file
105
drivers/i2c/busses/i2c-designware-core.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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);
|
392
drivers/i2c/busses/i2c-designware-pcidrv.c
Normal file
392
drivers/i2c/busses/i2c-designware-pcidrv.c
Normal file
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* 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");
|
215
drivers/i2c/busses/i2c-designware-platdrv.c
Normal file
215
drivers/i2c/busses/i2c-designware-platdrv.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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 @@
|
|||
#define TEN_BIT_ADDR_DEFAULT 0xF000
|
||||
#define TEN_BIT_ADDR_MASK 0xF0
|
||||
#define PCH_START 0x0020
|
||||
#define PCH_RESTART 0x0004
|
||||
#define PCH_ESR_START 0x0001
|
||||
#define PCH_BUFF_START 0x1
|
||||
#define PCH_REPSTART 0x0004
|
||||
|
@ -273,23 +274,24 @@ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
|
|||
s32 timeout)
|
||||
{
|
||||
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 */
|
||||
ktime_t ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
|
||||
ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
|
||||
do {
|
||||
if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
|
||||
break;
|
||||
msleep(20);
|
||||
if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
|
||||
return 0;
|
||||
} while (ktime_lt(ktime_get(), ns_val));
|
||||
|
||||
pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
|
||||
pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
|
||||
pch_i2c_init(adap);
|
||||
|
||||
if (timeout == 0) {
|
||||
pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
{
|
||||
s32 ret;
|
||||
long ret;
|
||||
ret = wait_event_timeout(pch_event,
|
||||
(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) {
|
||||
pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
|
||||
adap->pch_event_flag = 0;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (adap->pch_event_flag & I2C_ERROR_MASK) {
|
||||
pch_err(adap, "error bits set: %x\n", adap->pch_event_flag);
|
||||
adap->pch_event_flag = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -394,6 +394,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
|
|||
u32 addr_2_msb;
|
||||
u32 addr_8_lsb;
|
||||
s32 wrcount;
|
||||
s32 rtn;
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
|
||||
length = msgs->len;
|
||||
|
@ -412,15 +413,29 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
|
|||
}
|
||||
|
||||
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);
|
||||
if (first)
|
||||
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);
|
||||
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);
|
||||
return -ETIME;
|
||||
}
|
||||
|
@ -431,31 +446,52 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
|
|||
pch_i2c_start(adap);
|
||||
}
|
||||
|
||||
if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
|
||||
(pch_i2c_getack(adap) == 0)) {
|
||||
for (wrcount = 0; wrcount < length; ++wrcount) {
|
||||
/* write buffer value to I2C data register */
|
||||
iowrite32(buf[wrcount], p + PCH_I2CDR);
|
||||
pch_dbg(adap, "writing %x to Data register\n",
|
||||
buf[wrcount]);
|
||||
|
||||
if (pch_i2c_wait_for_xfer_complete(adap) != 0)
|
||||
return -ETIME;
|
||||
|
||||
if (pch_i2c_getack(adap))
|
||||
return -EIO;
|
||||
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;
|
||||
}
|
||||
|
||||
/* check if this is the last message */
|
||||
if (last)
|
||||
pch_i2c_stop(adap);
|
||||
else
|
||||
pch_i2c_repstart(adap);
|
||||
} 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);
|
||||
return -EIO;
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
for (wrcount = 0; wrcount < length; ++wrcount) {
|
||||
/* write buffer value to I2C data register */
|
||||
iowrite32(buf[wrcount], p + PCH_I2CDR);
|
||||
pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]);
|
||||
|
||||
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;
|
||||
}
|
||||
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 */
|
||||
if (last)
|
||||
pch_i2c_stop(adap);
|
||||
else
|
||||
pch_i2c_repstart(adap);
|
||||
|
||||
pch_dbg(adap, "return=%d\n", wrcount);
|
||||
|
||||
return wrcount;
|
||||
|
@ -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_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.
|
||||
* @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,
|
|||
u32 length;
|
||||
u32 addr;
|
||||
u32 addr_2_msb;
|
||||
u32 addr_8_lsb;
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
s32 rtn;
|
||||
|
||||
length = msgs->len;
|
||||
buf = msgs->buf;
|
||||
|
@ -515,9 +566,55 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
|||
}
|
||||
|
||||
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);
|
||||
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 {
|
||||
/* 7 address bits + R/W bit */
|
||||
addr = (((addr) << 1) | (I2C_RD));
|
||||
|
@ -528,56 +625,81 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
|||
if (first)
|
||||
pch_i2c_start(adap);
|
||||
|
||||
if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
|
||||
(pch_i2c_getack(adap) == 0)) {
|
||||
pch_dbg(adap, "return %d\n", 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 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) {
|
||||
pch_i2c_stop(adap);
|
||||
ioread32(p + PCH_I2CDR); /* Dummy read needs */
|
||||
if (length == 0) {
|
||||
pch_i2c_stop(adap);
|
||||
ioread32(p + PCH_I2CDR); /* Dummy read needs */
|
||||
|
||||
count = length;
|
||||
} else {
|
||||
int read_index;
|
||||
int loop;
|
||||
pch_i2c_sendack(adap);
|
||||
|
||||
/* Dummy read */
|
||||
for (loop = 1, read_index = 0; loop < length; loop++) {
|
||||
buf[read_index] = ioread32(p + PCH_I2CDR);
|
||||
|
||||
if (loop != 1)
|
||||
read_index++;
|
||||
|
||||
if (pch_i2c_wait_for_xfer_complete(adap) != 0) {
|
||||
pch_i2c_stop(adap);
|
||||
return -ETIME;
|
||||
}
|
||||
} /* end for */
|
||||
|
||||
pch_i2c_sendnack(adap);
|
||||
count = length;
|
||||
} else {
|
||||
int read_index;
|
||||
int loop;
|
||||
pch_i2c_sendack(adap);
|
||||
|
||||
/* Dummy read */
|
||||
for (loop = 1, read_index = 0; loop < length; loop++) {
|
||||
buf[read_index] = ioread32(p + PCH_I2CDR);
|
||||
|
||||
if (length != 1)
|
||||
if (loop != 1)
|
||||
read_index++;
|
||||
|
||||
if (pch_i2c_wait_for_xfer_complete(adap) == 0) {
|
||||
if (last)
|
||||
pch_i2c_stop(adap);
|
||||
else
|
||||
pch_i2c_repstart(adap);
|
||||
|
||||
buf[read_index++] = ioread32(p + PCH_I2CDR);
|
||||
count = read_index;
|
||||
} else {
|
||||
count = -ETIME;
|
||||
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;
|
||||
}
|
||||
|
||||
} /* end for */
|
||||
|
||||
pch_i2c_sendnack(adap);
|
||||
|
||||
buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */
|
||||
|
||||
if (length != 1)
|
||||
read_index++;
|
||||
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
count = -ETIME;
|
||||
pch_i2c_stop(adap);
|
||||
|
||||
if (last)
|
||||
pch_i2c_stop(adap);
|
||||
else
|
||||
pch_i2c_repstart(adap);
|
||||
|
||||
buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */
|
||||
count = read_index;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
|
|
@ -387,7 +387,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev)
|
|||
dev->irq = 0;
|
||||
|
||||
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);
|
||||
if (unlikely(ret))
|
||||
goto err_unmap;
|
||||
|
|
|
@ -48,6 +48,9 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.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/hardware.h>
|
||||
|
@ -125,6 +128,11 @@ struct imx_i2c_struct {
|
|||
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 ***************************************
|
||||
*******************************************************************************/
|
||||
|
||||
|
@ -466,10 +474,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct imx_i2c_struct *i2c_imx;
|
||||
struct resource *res;
|
||||
struct imxi2c_platform_data *pdata;
|
||||
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
|
||||
void __iomem *base;
|
||||
resource_size_t res_size;
|
||||
int irq;
|
||||
int irq, bitrate;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&pdev->dev, "<%s>\n", __func__);
|
||||
|
@ -485,19 +493,11 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
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);
|
||||
|
||||
if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
|
||||
ret = -EBUSY;
|
||||
goto fail0;
|
||||
dev_err(&pdev->dev, "request_mem_region failed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
base = ioremap(res->start, res_size);
|
||||
|
@ -520,6 +520,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
i2c_imx->adapter.algo = &i2c_imx_algo;
|
||||
i2c_imx->adapter.dev.parent = &pdev->dev;
|
||||
i2c_imx->adapter.nr = pdev->id;
|
||||
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
|
||||
i2c_imx->irq = irq;
|
||||
i2c_imx->base = base;
|
||||
i2c_imx->res = res;
|
||||
|
@ -546,10 +547,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
|
||||
|
||||
/* Set up clock divider */
|
||||
if (pdata && pdata->bitrate)
|
||||
i2c_imx_set_clk(i2c_imx, pdata->bitrate);
|
||||
else
|
||||
i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);
|
||||
bitrate = IMX_I2C_BIT_RATE;
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"clock-frequency", &bitrate);
|
||||
if (ret < 0 && pdata && pdata->bitrate)
|
||||
bitrate = pdata->bitrate;
|
||||
i2c_imx_set_clk(i2c_imx, bitrate);
|
||||
|
||||
/* Set up chip registers to defaults */
|
||||
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
|
||||
|
@ -562,6 +565,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
goto fail5;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&i2c_imx->adapter);
|
||||
|
||||
/* Set up platform driver data */
|
||||
platform_set_drvdata(pdev, i2c_imx);
|
||||
|
||||
|
@ -586,16 +591,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
iounmap(base);
|
||||
fail1:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
fail0:
|
||||
if (pdata && pdata->exit)
|
||||
pdata->exit(&pdev->dev);
|
||||
return ret; /* Return error number */
|
||||
}
|
||||
|
||||
static int __exit i2c_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
|
||||
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
/* remove adapter */
|
||||
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
|
||||
|
@ -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_I2SR);
|
||||
|
||||
/* Shut down hardware */
|
||||
if (pdata && pdata->exit)
|
||||
pdata->exit(&pdev->dev);
|
||||
|
||||
clk_put(i2c_imx->clk);
|
||||
|
||||
iounmap(i2c_imx->base);
|
||||
|
@ -628,6 +625,7 @@ static struct platform_driver i2c_imx_driver = {
|
|||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = i2c_imx_dt_ids,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -63,11 +63,11 @@
|
|||
/* Master controller (MCR) register */
|
||||
#define I2C_MCR_OP (0x1 << 0) /* Operation */
|
||||
#define I2C_MCR_A7 (0x7f << 1) /* 7-bit address */
|
||||
#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */
|
||||
#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */
|
||||
#define I2C_MCR_SB (0x1 << 11) /* Extended address */
|
||||
#define I2C_MCR_AM (0x3 << 12) /* Address type */
|
||||
#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */
|
||||
#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */
|
||||
#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */
|
||||
#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */
|
||||
|
||||
/* Status register (SR) */
|
||||
#define I2C_SR_OP (0x3 << 0) /* Operation */
|
||||
|
@ -77,7 +77,7 @@
|
|||
#define I2C_SR_LENGTH (0x7ff << 9) /* Transfer length */
|
||||
|
||||
/* Interrupt mask set/clear (IMSCR) bits */
|
||||
#define I2C_IT_TXFE (0x1 << 0)
|
||||
#define I2C_IT_TXFE (0x1 << 0)
|
||||
#define I2C_IT_TXFNE (0x1 << 1)
|
||||
#define I2C_IT_TXFF (0x1 << 2)
|
||||
#define I2C_IT_TXFOVR (0x1 << 3)
|
||||
|
@ -135,31 +135,31 @@ struct i2c_nmk_client {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct nmk_i2c_dev - private data structure of the controller
|
||||
* @pdev: parent platform device
|
||||
* @adap: corresponding I2C adapter
|
||||
* @irq: interrupt line for the controller
|
||||
* @virtbase: virtual io memory area
|
||||
* @clk: hardware i2c block clock
|
||||
* @cfg: machine provided controller configuration
|
||||
* @cli: holder of client specific data
|
||||
* @stop: stop condition
|
||||
* @xfer_complete: acknowledge completion for a I2C message
|
||||
* @result: controller propogated result
|
||||
* @regulator: pointer to i2c regulator
|
||||
* @busy: Busy doing transfer
|
||||
* struct nmk_i2c_dev - private data structure of the controller.
|
||||
* @pdev: parent platform device.
|
||||
* @adap: corresponding I2C adapter.
|
||||
* @irq: interrupt line for the controller.
|
||||
* @virtbase: virtual io memory area.
|
||||
* @clk: hardware i2c block clock.
|
||||
* @cfg: machine provided controller configuration.
|
||||
* @cli: holder of client specific data.
|
||||
* @stop: stop condition.
|
||||
* @xfer_complete: acknowledge completion for a I2C message.
|
||||
* @result: controller propogated result.
|
||||
* @regulator: pointer to i2c regulator.
|
||||
* @busy: Busy doing transfer.
|
||||
*/
|
||||
struct nmk_i2c_dev {
|
||||
struct platform_device *pdev;
|
||||
struct i2c_adapter adap;
|
||||
int irq;
|
||||
struct i2c_adapter adap;
|
||||
int irq;
|
||||
void __iomem *virtbase;
|
||||
struct clk *clk;
|
||||
struct nmk_i2c_controller cfg;
|
||||
struct i2c_nmk_client cli;
|
||||
int stop;
|
||||
int stop;
|
||||
struct completion xfer_complete;
|
||||
int result;
|
||||
int result;
|
||||
struct regulator *regulator;
|
||||
bool busy;
|
||||
};
|
||||
|
@ -217,8 +217,9 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
dev_err(&dev->pdev->dev, "flushing operation timed out "
|
||||
"giving up after %d attempts", LOOP_ATTEMPTS);
|
||||
dev_err(&dev->pdev->dev,
|
||||
"flushing operation timed out giving up after %d attempts",
|
||||
LOOP_ATTEMPTS);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -270,7 +271,7 @@ static int init_hw(struct nmk_i2c_dev *dev)
|
|||
}
|
||||
|
||||
/* enable peripheral, master mode operation */
|
||||
#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE)
|
||||
#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE)
|
||||
|
||||
/**
|
||||
* load_i2c_mcr_reg() - load the MCR register
|
||||
|
@ -363,8 +364,8 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
|
|||
* and high speed (up to 3.4 Mb/s)
|
||||
*/
|
||||
if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
|
||||
dev_err(&dev->pdev->dev, "do not support this mode "
|
||||
"defaulting to std. mode\n");
|
||||
dev_err(&dev->pdev->dev,
|
||||
"do not support this mode defaulting to std. mode\n");
|
||||
brcr2 = i2c_clk/(100000 * 2) & 0xffff;
|
||||
writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
|
||||
writel(I2C_FREQ_MODE_STANDARD << 4,
|
||||
|
@ -423,7 +424,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
|
|||
|
||||
if (timeout < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
"wait_for_completion_timeout"
|
||||
"wait_for_completion_timeout "
|
||||
"returned %d waiting for event\n", timeout);
|
||||
status = timeout;
|
||||
}
|
||||
|
@ -556,8 +557,8 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
|
|||
if (((i2c_sr >> 2) & 0x3) == 0x3) {
|
||||
/* get the abort cause */
|
||||
cause = (i2c_sr >> 4) & 0x7;
|
||||
dev_err(&dev->pdev->dev, "%s\n", cause
|
||||
>= ARRAY_SIZE(abort_causes) ?
|
||||
dev_err(&dev->pdev->dev, "%s\n",
|
||||
cause >= ARRAY_SIZE(abort_causes) ?
|
||||
"unknown reason" :
|
||||
abort_causes[cause]);
|
||||
}
|
||||
|
@ -582,13 +583,13 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
|
|||
*
|
||||
* NOTE:
|
||||
* READ TRANSFER : We impose a restriction of the first message to be the
|
||||
* index message for any read transaction.
|
||||
* - a no index is coded as '0',
|
||||
* - 2byte big endian index is coded as '3'
|
||||
* !!! msg[0].buf holds the actual index.
|
||||
* This is compatible with generic messages of smbus emulator
|
||||
* that send a one byte index.
|
||||
* eg. a I2C transation to read 2 bytes from index 0
|
||||
* index message for any read transaction.
|
||||
* - a no index is coded as '0',
|
||||
* - 2byte big endian index is coded as '3'
|
||||
* !!! msg[0].buf holds the actual index.
|
||||
* This is compatible with generic messages of smbus emulator
|
||||
* that send a one byte index.
|
||||
* eg. a I2C transation to read 2 bytes from index 0
|
||||
* idx = 0;
|
||||
* msg[0].addr = client->addr;
|
||||
* msg[0].flags = 0x0;
|
||||
|
@ -644,8 +645,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
|
||||
for (i = 0; i < num_msgs; i++) {
|
||||
if (unlikely(msgs[i].flags & I2C_M_TEN)) {
|
||||
dev_err(&dev->pdev->dev, "10 bit addressing"
|
||||
"not supported\n");
|
||||
dev_err(&dev->pdev->dev,
|
||||
"10 bit addressing not supported\n");
|
||||
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
|
@ -789,8 +790,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
|||
|
||||
if (dev->cli.count) {
|
||||
dev->result = -EIO;
|
||||
dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
|
||||
"xfered\n", dev->cli.count);
|
||||
dev_err(&dev->pdev->dev,
|
||||
"%lu bytes still remain to be xfered\n",
|
||||
dev->cli.count);
|
||||
(void) init_hw(dev);
|
||||
}
|
||||
complete(&dev->xfer_complete);
|
||||
|
@ -923,7 +925,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (request_mem_region(res->start, resource_size(res),
|
||||
DRIVER_NAME "I/O region") == NULL) {
|
||||
DRIVER_NAME "I/O region") == NULL) {
|
||||
ret = -EBUSY;
|
||||
goto err_no_region;
|
||||
}
|
||||
|
@ -935,7 +937,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
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);
|
||||
if (ret) {
|
||||
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)
|
|||
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
||||
dev_info(&pdev->dev, "initialize %s on virtual "
|
||||
"base %p\n", adap->name, dev->virtbase);
|
||||
dev_info(&pdev->dev,
|
||||
"initialize %s on virtual base %p\n",
|
||||
adap->name, dev->virtbase);
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret) {
|
||||
|
|
|
@ -610,7 +610,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
|
|||
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);
|
||||
|
||||
if (ret != 0) {
|
||||
|
|
|
@ -42,12 +42,12 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
|
||||
/* I2C controller revisions */
|
||||
#define OMAP_I2C_REV_2 0x20
|
||||
#define OMAP_I2C_OMAP1_REV_2 0x20
|
||||
|
||||
/* I2C controller revisions present on specific hardware */
|
||||
#define OMAP_I2C_REV_ON_2430 0x36
|
||||
#define OMAP_I2C_REV_ON_3430 0x3C
|
||||
#define OMAP_I2C_REV_ON_4430 0x40
|
||||
#define OMAP_I2C_REV_ON_3530_4430 0x40
|
||||
|
||||
/* timeout waiting for the controller to respond */
|
||||
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
@ -72,11 +72,12 @@ enum {
|
|||
OMAP_I2C_SCLH_REG,
|
||||
OMAP_I2C_SYSTEST_REG,
|
||||
OMAP_I2C_BUFSTAT_REG,
|
||||
OMAP_I2C_REVNB_LO,
|
||||
OMAP_I2C_REVNB_HI,
|
||||
OMAP_I2C_IRQSTATUS_RAW,
|
||||
OMAP_I2C_IRQENABLE_SET,
|
||||
OMAP_I2C_IRQENABLE_CLR,
|
||||
/* only on OMAP4430 */
|
||||
OMAP_I2C_IP_V2_REVNB_LO,
|
||||
OMAP_I2C_IP_V2_REVNB_HI,
|
||||
OMAP_I2C_IP_V2_IRQSTATUS_RAW,
|
||||
OMAP_I2C_IP_V2_IRQENABLE_SET,
|
||||
OMAP_I2C_IP_V2_IRQENABLE_CLR,
|
||||
};
|
||||
|
||||
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
|
||||
|
@ -193,7 +194,6 @@ struct omap_i2c_dev {
|
|||
*/
|
||||
u8 rev;
|
||||
unsigned b_hw:1; /* bad h/w fixes */
|
||||
unsigned idle:1;
|
||||
u16 iestate; /* Saved interrupt register */
|
||||
u16 pscstate;
|
||||
u16 scllstate;
|
||||
|
@ -204,7 +204,7 @@ struct omap_i2c_dev {
|
|||
u16 errata;
|
||||
};
|
||||
|
||||
static const u8 reg_map[] = {
|
||||
static const u8 reg_map_ip_v1[] = {
|
||||
[OMAP_I2C_REV_REG] = 0x00,
|
||||
[OMAP_I2C_IE_REG] = 0x01,
|
||||
[OMAP_I2C_STAT_REG] = 0x02,
|
||||
|
@ -225,7 +225,7 @@ static const u8 reg_map[] = {
|
|||
[OMAP_I2C_BUFSTAT_REG] = 0x10,
|
||||
};
|
||||
|
||||
static const u8 omap4_reg_map[] = {
|
||||
static const u8 reg_map_ip_v2[] = {
|
||||
[OMAP_I2C_REV_REG] = 0x04,
|
||||
[OMAP_I2C_IE_REG] = 0x2c,
|
||||
[OMAP_I2C_STAT_REG] = 0x28,
|
||||
|
@ -244,11 +244,11 @@ static const u8 omap4_reg_map[] = {
|
|||
[OMAP_I2C_SCLH_REG] = 0xb8,
|
||||
[OMAP_I2C_SYSTEST_REG] = 0xbC,
|
||||
[OMAP_I2C_BUFSTAT_REG] = 0xc0,
|
||||
[OMAP_I2C_REVNB_LO] = 0x00,
|
||||
[OMAP_I2C_REVNB_HI] = 0x04,
|
||||
[OMAP_I2C_IRQSTATUS_RAW] = 0x24,
|
||||
[OMAP_I2C_IRQENABLE_SET] = 0x2c,
|
||||
[OMAP_I2C_IRQENABLE_CLR] = 0x30,
|
||||
[OMAP_I2C_IP_V2_REVNB_LO] = 0x00,
|
||||
[OMAP_I2C_IP_V2_REVNB_HI] = 0x04,
|
||||
[OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24,
|
||||
[OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c,
|
||||
[OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30,
|
||||
};
|
||||
|
||||
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
|
||||
|
@ -266,17 +266,11 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
|
|||
|
||||
static void omap_i2c_unidle(struct omap_i2c_dev *dev)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct omap_i2c_bus_platform_data *pdata;
|
||||
|
||||
WARN_ON(!dev->idle);
|
||||
pdata = dev->dev->platform_data;
|
||||
|
||||
pdev = to_platform_device(dev->dev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
|
||||
|
@ -286,7 +280,6 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
|
|||
omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
}
|
||||
dev->idle = 0;
|
||||
|
||||
/*
|
||||
* Don't write to this register if the IE state is 0 as it can
|
||||
|
@ -298,32 +291,25 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
|
|||
|
||||
static void omap_i2c_idle(struct omap_i2c_dev *dev)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct omap_i2c_bus_platform_data *pdata;
|
||||
u16 iv;
|
||||
|
||||
WARN_ON(dev->idle);
|
||||
|
||||
pdev = to_platform_device(dev->dev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
pdata = dev->dev->platform_data;
|
||||
|
||||
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
|
||||
if (dev->rev >= OMAP_I2C_REV_ON_4430)
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
|
||||
if (pdata->rev == OMAP_I2C_IP_VERSION_2)
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
|
||||
else
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
|
||||
|
||||
if (dev->rev < OMAP_I2C_REV_2) {
|
||||
if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
|
||||
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
|
||||
} else {
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
|
||||
|
||||
/* Flush posted write before the dev->idle store occurs */
|
||||
/* Flush posted write */
|
||||
omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
|
||||
}
|
||||
dev->idle = 1;
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
}
|
||||
|
||||
static int omap_i2c_init(struct omap_i2c_dev *dev)
|
||||
|
@ -334,8 +320,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
unsigned long timeout;
|
||||
unsigned long internal_clk = 0;
|
||||
struct clk *fclk;
|
||||
struct omap_i2c_bus_platform_data *pdata;
|
||||
|
||||
if (dev->rev >= OMAP_I2C_REV_2) {
|
||||
pdata = dev->dev->platform_data;
|
||||
|
||||
if (dev->rev >= OMAP_I2C_OMAP1_REV_2) {
|
||||
/* Disable I2C controller before soft reset */
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
|
||||
omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
|
||||
|
@ -378,12 +367,13 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
* REVISIT: Some wkup sources might not be needed.
|
||||
*/
|
||||
dev->westate = OMAP_I2C_WE_ALL;
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
|
||||
dev->westate);
|
||||
}
|
||||
}
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
|
||||
if (cpu_class_is_omap1()) {
|
||||
if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
|
||||
/*
|
||||
* The I2C functional clock is the armxor_ck, so there's
|
||||
* no need to get "armxor_ck" separately. Now, if OMAP2420
|
||||
|
@ -407,7 +397,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
psc = fclk_rate / 12000000;
|
||||
}
|
||||
|
||||
if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
|
||||
if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
|
||||
|
||||
/*
|
||||
* HSI2C controller internal clk rate should be 19.2 Mhz for
|
||||
|
@ -415,7 +405,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
* to get longer filter period for better noise suppression.
|
||||
* The filter is iclk (fclk for HS) period.
|
||||
*/
|
||||
if (dev->speed > 400 || cpu_is_omap2430())
|
||||
if (dev->speed > 400 ||
|
||||
pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
|
||||
internal_clk = 19200;
|
||||
else if (dev->speed > 100)
|
||||
internal_clk = 9600;
|
||||
|
@ -484,7 +475,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
|
||||
dev->errata = 0;
|
||||
|
||||
if (cpu_is_omap2430() || cpu_is_omap34xx())
|
||||
if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
|
||||
dev->errata |= I2C_OMAP_ERRATA_I207;
|
||||
|
||||
/* Enable interrupts */
|
||||
|
@ -493,7 +484,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
|
||||
(OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
|
||||
if (cpu_is_omap34xx()) {
|
||||
if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
|
||||
dev->pscstate = psc;
|
||||
dev->scllstate = scll;
|
||||
dev->sclhstate = sclh;
|
||||
|
@ -642,7 +633,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
int i;
|
||||
int r;
|
||||
|
||||
omap_i2c_unidle(dev);
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
|
||||
r = omap_i2c_wait_for_bb(dev);
|
||||
if (r < 0)
|
||||
|
@ -665,7 +656,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
|
||||
omap_i2c_wait_for_bb(dev);
|
||||
out:
|
||||
omap_i2c_idle(dev);
|
||||
pm_runtime_put(dev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -720,12 +711,12 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)
|
|||
#ifdef CONFIG_ARCH_OMAP15XX
|
||||
|
||||
static irqreturn_t
|
||||
omap_i2c_rev1_isr(int this_irq, void *dev_id)
|
||||
omap_i2c_omap1_isr(int this_irq, void *dev_id)
|
||||
{
|
||||
struct omap_i2c_dev *dev = dev_id;
|
||||
u16 iv, w;
|
||||
|
||||
if (dev->idle)
|
||||
if (pm_runtime_suspended(dev->dev))
|
||||
return IRQ_NONE;
|
||||
|
||||
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
|
||||
|
@ -774,7 +765,7 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
#else
|
||||
#define omap_i2c_rev1_isr NULL
|
||||
#define omap_i2c_omap1_isr NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -813,8 +804,11 @@ omap_i2c_isr(int this_irq, void *dev_id)
|
|||
u16 bits;
|
||||
u16 stat, w;
|
||||
int err, count = 0;
|
||||
struct omap_i2c_bus_platform_data *pdata;
|
||||
|
||||
if (dev->idle)
|
||||
pdata = dev->dev->platform_data;
|
||||
|
||||
if (pm_runtime_suspended(dev->dev))
|
||||
return IRQ_NONE;
|
||||
|
||||
bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
|
||||
|
@ -881,8 +875,8 @@ omap_i2c_isr(int this_irq, void *dev_id)
|
|||
* Data reg in 2430, omap3 and
|
||||
* omap4 is 8 bit wide
|
||||
*/
|
||||
if (cpu_class_is_omap1() ||
|
||||
cpu_is_omap2420()) {
|
||||
if (pdata->flags &
|
||||
OMAP_I2C_FLAG_16BIT_DATA_REG) {
|
||||
if (dev->buf_len) {
|
||||
*dev->buf++ = w >> 8;
|
||||
dev->buf_len--;
|
||||
|
@ -924,8 +918,8 @@ omap_i2c_isr(int this_irq, void *dev_id)
|
|||
* Data reg in 2430, omap3 and
|
||||
* omap4 is 8 bit wide
|
||||
*/
|
||||
if (cpu_class_is_omap1() ||
|
||||
cpu_is_omap2420()) {
|
||||
if (pdata->flags &
|
||||
OMAP_I2C_FLAG_16BIT_DATA_REG) {
|
||||
if (dev->buf_len) {
|
||||
w |= *dev->buf++ << 8;
|
||||
dev->buf_len--;
|
||||
|
@ -1016,7 +1010,6 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
dev->speed = speed;
|
||||
dev->idle = 1;
|
||||
dev->dev = &pdev->dev;
|
||||
dev->irq = irq->start;
|
||||
dev->base = ioremap(mem->start, resource_size(mem));
|
||||
|
@ -1027,27 +1020,22 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
if (cpu_is_omap7xx())
|
||||
dev->reg_shift = 1;
|
||||
else if (cpu_is_omap44xx())
|
||||
dev->reg_shift = 0;
|
||||
else
|
||||
dev->reg_shift = 2;
|
||||
dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
|
||||
|
||||
if (cpu_is_omap44xx())
|
||||
dev->regs = (u8 *) omap4_reg_map;
|
||||
if (pdata->rev == OMAP_I2C_IP_VERSION_2)
|
||||
dev->regs = (u8 *)reg_map_ip_v2;
|
||||
else
|
||||
dev->regs = (u8 *) reg_map;
|
||||
dev->regs = (u8 *)reg_map_ip_v1;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
omap_i2c_unidle(dev);
|
||||
pm_runtime_enable(dev->dev);
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
|
||||
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
|
||||
|
||||
if (dev->rev <= OMAP_I2C_REV_ON_3430)
|
||||
dev->errata |= I2C_OMAP3_1P153;
|
||||
|
||||
if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
|
||||
if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) {
|
||||
u16 s;
|
||||
|
||||
/* Set up the fifo size - Get total size */
|
||||
|
@ -1059,7 +1047,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
* size. This is to ensure that we can handle the status on int
|
||||
* call back latencies.
|
||||
*/
|
||||
if (dev->rev >= OMAP_I2C_REV_ON_4430) {
|
||||
if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) {
|
||||
dev->fifo_size = 0;
|
||||
dev->b_hw = 0; /* Disable hardware fixes */
|
||||
} else {
|
||||
|
@ -1075,7 +1063,8 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
/* reset ASAP, clearing any IRQs */
|
||||
omap_i2c_init(dev);
|
||||
|
||||
isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr;
|
||||
isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
|
||||
omap_i2c_isr;
|
||||
r = request_irq(dev->irq, isr, 0, pdev->name, dev);
|
||||
|
||||
if (r) {
|
||||
|
@ -1083,10 +1072,10 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
goto err_unuse_clocks;
|
||||
}
|
||||
|
||||
dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
|
||||
pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed);
|
||||
dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
|
||||
pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
|
||||
|
||||
omap_i2c_idle(dev);
|
||||
pm_runtime_put(dev->dev);
|
||||
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
@ -1110,7 +1099,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
free_irq(dev->irq, dev);
|
||||
err_unuse_clocks:
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
omap_i2c_idle(dev);
|
||||
pm_runtime_put(dev->dev);
|
||||
iounmap(dev->base);
|
||||
err_free_mem:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
@ -1139,12 +1128,43 @@ omap_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int omap_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
|
||||
|
||||
omap_i2c_idle(_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
|
||||
|
||||
omap_i2c_unidle(_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops omap_i2c_pm_ops = {
|
||||
.runtime_suspend = omap_i2c_runtime_suspend,
|
||||
.runtime_resume = omap_i2c_runtime_resume,
|
||||
};
|
||||
#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
|
||||
#else
|
||||
#define OMAP_I2C_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver omap_i2c_driver = {
|
||||
.probe = omap_i2c_probe,
|
||||
.remove = omap_i2c_remove,
|
||||
.driver = {
|
||||
.name = "omap_i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = OMAP_I2C_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -306,7 +306,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
|
|||
pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
|
||||
if (pmcmsptwi_data.irq) {
|
||||
rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
|
||||
IRQF_SHARED | IRQF_SAMPLE_RANDOM,
|
||||
pldev->name, &pmcmsptwi_data);
|
||||
if (rc == 0) {
|
||||
/*
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
|
||||
|
@ -78,6 +80,8 @@ struct s3c24xx_i2c {
|
|||
struct resource *ioarea;
|
||||
struct i2c_adapter adap;
|
||||
|
||||
struct s3c2410_platform_i2c *pdata;
|
||||
int gpios[2];
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
struct notifier_block freq_transition;
|
||||
#endif
|
||||
|
@ -95,6 +99,12 @@ static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
|
|||
struct platform_device *pdev = to_platform_device(i2c->dev);
|
||||
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;
|
||||
return type == TYPE_S3C2440;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
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 int divs, div1;
|
||||
unsigned long target_frequency;
|
||||
|
@ -741,6 +751,49 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
|
|||
}
|
||||
#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
|
||||
*
|
||||
* initialise the controller, set the IO lines and frequency
|
||||
|
@ -754,12 +807,15 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
|
|||
|
||||
/* get the plafrom data */
|
||||
|
||||
pdata = i2c->dev->platform_data;
|
||||
pdata = i2c->pdata;
|
||||
|
||||
/* inititalise the gpio */
|
||||
|
||||
if (pdata->cfg_gpio)
|
||||
pdata->cfg_gpio(to_platform_device(i2c->dev));
|
||||
else
|
||||
if (s3c24xx_i2c_parse_dt_gpio(i2c))
|
||||
return -EINVAL;
|
||||
|
||||
/* write slave address */
|
||||
|
||||
|
@ -785,6 +841,34 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
|
|||
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
|
||||
*
|
||||
* called by the bus driver when a suitable device is found
|
||||
|
@ -793,14 +877,16 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
|
|||
static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c24xx_i2c *i2c;
|
||||
struct s3c2410_platform_i2c *pdata;
|
||||
struct s3c2410_platform_i2c *pdata = NULL;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data\n");
|
||||
return -EINVAL;
|
||||
if (!pdev->dev.of_node) {
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
|
||||
|
@ -809,6 +895,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
|||
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));
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &s3c24xx_i2c_algorithm;
|
||||
|
@ -883,7 +980,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
|||
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);
|
||||
|
||||
if (ret != 0) {
|
||||
|
@ -903,7 +1000,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
|||
* 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);
|
||||
if (ret < 0) {
|
||||
|
@ -911,6 +1009,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
|||
goto err_cpufreq;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&i2c->adap);
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
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)
|
|||
iounmap(i2c->regs);
|
||||
|
||||
release_resource(i2c->ioarea);
|
||||
s3c24xx_i2c_dt_gpio_free(i2c);
|
||||
kfree(i2c->ioarea);
|
||||
kfree(i2c);
|
||||
|
||||
|
@ -1012,6 +1112,17 @@ static struct platform_device_id 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 = {
|
||||
.probe = s3c24xx_i2c_probe,
|
||||
.remove = s3c24xx_i2c_remove,
|
||||
|
@ -1020,6 +1131,7 @@ static struct platform_driver s3c24xx_i2c_driver = {
|
|||
.owner = THIS_MODULE,
|
||||
.name = "s3c-i2c",
|
||||
.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)
|
|||
}
|
||||
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)) {
|
||||
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
|
||||
ret = -EBUSY;
|
||||
|
|
|
@ -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))) {
|
||||
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)) {
|
||||
for (n--; n >= res->start; n--)
|
||||
free_irq(n, dev);
|
||||
|
|
|
@ -916,7 +916,7 @@ stu300_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
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)) {
|
||||
ret = -EIO;
|
||||
goto err_no_irq;
|
||||
|
|
|
@ -566,7 +566,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
struct clk *clk;
|
||||
struct clk *i2c_clk;
|
||||
const unsigned int *prop;
|
||||
void *base;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
int ret = 0;
|
||||
|
||||
|
|
|
@ -32,10 +32,9 @@
|
|||
|
||||
struct omap_i2c_bus_platform_data {
|
||||
u32 clkrate;
|
||||
u32 rev;
|
||||
u32 flags;
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue