Merge branch 'i2c-embedded/for-next' of git://git.pengutronix.de/git/wsa/linux
Pull embedded i2c changes from Wolfram Sang: "Changes for the "embedded" part of the I2C subsystem: - lots of devicetree conversions of drivers (and preparations for that) - big cleanups for drivers for OMAP, Tegra, Nomadik, Blackfin - Rafael's struct dev_pm_ops conversion patches for I2C - usual driver cleanups and fixes All patches have been in linux-next for an apropriate time and all patches touching files outside of i2c-folders should have proper acks from the maintainers." * 'i2c-embedded/for-next' of git://git.pengutronix.de/git/wsa/linux: (60 commits) Revert "i2c: tegra: convert normal suspend/resume to *_noirq" I2C: MV64XYZ: Add Device Tree support i2c: stu300: use devm managed resources i2c: i2c-ocores: support for 16bit and 32bit IO V4L/DVB: mfd: use reg_shift instead of regstep i2c: i2c-ocores: Use reg-shift property i2c: i2c-ocores: DT bindings and minor fixes. i2c: mv64xxxx: remove EXPERIMENTAL tag i2c-s3c2410: Use plain pm_runtime_put() i2c: s3c2410: Fix pointer type passed to of_match_node() i2c: mxs: Set I2C timing registers for mxs-i2c i2c: i2c-bfin-twi: Move blackfin TWI register access Macro to head file. i2c: i2c-bfin-twi: Move TWI peripheral pin request array to platform data. i2c:i2c-bfin-twi: include twi head file i2c:i2c-bfin-twi: TWI fails to restart next transfer in high system load. i2c: i2c-bfin-twi: Tighten condition when failing I2C transfer if MEN bit is reset unexpectedly. i2c: i2c-bfin-twi: Break dead waiting loop if i2c device misbehaves. i2c: i2c-bfin-twi: Improve the patch for bug "Illegal i2c bus lock upon certain transfer scenarios". i2c: i2c-bfin-twi: Illegal i2c bus lock upon certain transfer scenarios. i2c-mv64xxxx: allow more than one driver instance ... Conflicts: drivers/i2c/busses/i2c-nomadik.c
This commit is contained in:
commit
a410963ba4
|
@ -4,6 +4,8 @@ Required properties:
|
|||
- compatible: Should be "fsl,<chip>-i2c"
|
||||
- reg: Should contain registers location and length
|
||||
- interrupts: Should contain ERROR and DMA interrupts
|
||||
- clock-frequency: Desired I2C bus clock frequency in Hz.
|
||||
Only 100000Hz and 400000Hz modes are supported.
|
||||
|
||||
Examples:
|
||||
|
||||
|
@ -13,4 +15,5 @@ i2c0: i2c@80058000 {
|
|||
compatible = "fsl,imx28-i2c";
|
||||
reg = <0x80058000 2000>;
|
||||
interrupts = <111 68>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
Device tree configuration for i2c-ocores
|
||||
|
||||
Required properties:
|
||||
- compatible : "opencores,i2c-ocores"
|
||||
- reg : bus address start and address range size of device
|
||||
- interrupts : interrupt number
|
||||
- clock-frequency : frequency of bus clock in Hz
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
|
||||
Optional properties:
|
||||
- reg-shift : device register offsets are shifted by this value
|
||||
- reg-io-width : io register width in bytes (1, 2 or 4)
|
||||
- regstep : deprecated, use reg-shift above
|
||||
|
||||
Example:
|
||||
|
||||
i2c0: ocores@a0000000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "opencores,i2c-ocores";
|
||||
reg = <0xa0000000 0x8>;
|
||||
interrupts = <10>;
|
||||
clock-frequency = <20000000>;
|
||||
|
||||
reg-shift = <0>; /* 8 bit registers */
|
||||
reg-io-width = <1>; /* 8 bit read/write */
|
||||
|
||||
dummy@60 {
|
||||
compatible = "dummy";
|
||||
reg = <0x60>;
|
||||
};
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
* I2C
|
||||
* Marvell MMP I2C controller
|
||||
|
||||
Required properties :
|
||||
|
||||
|
@ -32,3 +32,20 @@ Examples:
|
|||
interrupts = <58>;
|
||||
};
|
||||
|
||||
* Marvell MV64XXX I2C controller
|
||||
|
||||
Required properties :
|
||||
|
||||
- reg : Offset and length of the register set for the device
|
||||
- compatible : Should be "marvell,mv64xxx-i2c"
|
||||
- interrupts : The interrupt number
|
||||
- clock-frequency : Desired I2C bus clock frequency in Hz.
|
||||
|
||||
Examples:
|
||||
|
||||
i2c@11000 {
|
||||
compatible = "marvell,mv64xxx-i2c";
|
||||
reg = <0x11000 0x20>;
|
||||
interrupts = <29>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
|
|
@ -660,6 +660,7 @@
|
|||
compatible = "fsl,imx28-i2c";
|
||||
reg = <0x80058000 2000>;
|
||||
interrupts = <111 68>;
|
||||
clock-frequency = <100000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -669,6 +670,7 @@
|
|||
compatible = "fsl,imx28-i2c";
|
||||
reg = <0x8005a000 2000>;
|
||||
interrupts = <110 69>;
|
||||
clock-frequency = <100000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/i2c-nomadik.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/amba/pl022.h>
|
||||
|
@ -40,7 +41,6 @@
|
|||
#include <asm/mach/arch.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/ste_dma40.h>
|
||||
#include <plat/gpio-nomadik.h>
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <linux/platform_data/i2c-nomadik.h>
|
||||
#include <mach/crypto-ux500.h>
|
||||
|
||||
struct spi_master_cntlr;
|
||||
|
@ -56,27 +56,15 @@ dbx500_add_uart(struct device *parent, const char *name, resource_size_t base,
|
|||
|
||||
struct nmk_i2c_controller;
|
||||
|
||||
static inline struct platform_device *
|
||||
static inline struct amba_device *
|
||||
dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq,
|
||||
struct nmk_i2c_controller *data)
|
||||
{
|
||||
struct resource res[] = {
|
||||
DEFINE_RES_MEM(base, SZ_4K),
|
||||
DEFINE_RES_IRQ(irq),
|
||||
};
|
||||
/* Conjure a name similar to what the platform device used to have */
|
||||
char name[16];
|
||||
|
||||
struct platform_device_info pdevinfo = {
|
||||
.parent = parent,
|
||||
.name = "nmk-i2c",
|
||||
.id = id,
|
||||
.res = res,
|
||||
.num_res = ARRAY_SIZE(res),
|
||||
.data = data,
|
||||
.size_data = sizeof(*data),
|
||||
.dma_mask = DMA_BIT_MASK(32),
|
||||
};
|
||||
|
||||
return platform_device_register_full(&pdevinfo);
|
||||
snprintf(name, sizeof(name), "nmk-i2c.%d", id);
|
||||
return amba_apb_device_add(parent, name, base, SZ_4K, irq, 0, data, 0);
|
||||
}
|
||||
|
||||
static inline struct amba_device *
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*
|
||||
**/
|
||||
struct imxi2c_platform_data {
|
||||
int bitrate;
|
||||
u32 bitrate;
|
||||
};
|
||||
|
||||
#endif /* __ASM_ARCH_I2C_H_ */
|
||||
|
|
|
@ -462,7 +462,7 @@ config I2C_MPC
|
|||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
|
||||
depends on (MV64X60 || PLAT_ORION)
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||
|
@ -483,10 +483,11 @@ config I2C_MXS
|
|||
|
||||
config I2C_NOMADIK
|
||||
tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
|
||||
depends on PLAT_NOMADIK
|
||||
depends on ARM_AMBA
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
|
||||
I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
|
||||
as well as the STA2X11 PCIe I/O HUB.
|
||||
|
||||
config I2C_NUC900
|
||||
tristate "NUC900 I2C Driver"
|
||||
|
|
|
@ -279,30 +279,31 @@ static int __devexit at91_i2c_remove(struct platform_device *pdev)
|
|||
|
||||
/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
|
||||
|
||||
static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
static int at91_i2c_suspend(struct device *dev)
|
||||
{
|
||||
clk_disable(twi_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_i2c_resume(struct platform_device *pdev)
|
||||
static int at91_i2c_resume(struct device *dev)
|
||||
{
|
||||
return clk_enable(twi_clk);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume);
|
||||
#define AT91_I2C_PM (&at91_i2c_pm)
|
||||
|
||||
#else
|
||||
#define at91_i2c_suspend NULL
|
||||
#define at91_i2c_resume NULL
|
||||
#define AT91_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver at91_i2c_driver = {
|
||||
.probe = at91_i2c_probe,
|
||||
.remove = __devexit_p(at91_i2c_remove),
|
||||
.suspend = at91_i2c_suspend,
|
||||
.resume = at91_i2c_resume,
|
||||
.driver = {
|
||||
.name = "at91_i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = AT91_I2C_PM,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <asm/blackfin.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin_twi.h>
|
||||
|
||||
/* SMBus mode*/
|
||||
#define TWI_I2C_MODE_STANDARD 1
|
||||
|
@ -32,56 +33,6 @@
|
|||
#define TWI_I2C_MODE_COMBINED 3
|
||||
#define TWI_I2C_MODE_REPEAT 4
|
||||
|
||||
struct bfin_twi_iface {
|
||||
int irq;
|
||||
spinlock_t lock;
|
||||
char read_write;
|
||||
u8 command;
|
||||
u8 *transPtr;
|
||||
int readNum;
|
||||
int writeNum;
|
||||
int cur_mode;
|
||||
int manual_stop;
|
||||
int result;
|
||||
struct i2c_adapter adap;
|
||||
struct completion complete;
|
||||
struct i2c_msg *pmsg;
|
||||
int msg_num;
|
||||
int cur_msg;
|
||||
u16 saved_clkdiv;
|
||||
u16 saved_control;
|
||||
void __iomem *regs_base;
|
||||
};
|
||||
|
||||
|
||||
#define DEFINE_TWI_REG(reg, off) \
|
||||
static inline u16 read_##reg(struct bfin_twi_iface *iface) \
|
||||
{ return bfin_read16(iface->regs_base + (off)); } \
|
||||
static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
|
||||
{ bfin_write16(iface->regs_base + (off), v); }
|
||||
|
||||
DEFINE_TWI_REG(CLKDIV, 0x00)
|
||||
DEFINE_TWI_REG(CONTROL, 0x04)
|
||||
DEFINE_TWI_REG(SLAVE_CTL, 0x08)
|
||||
DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
|
||||
DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
|
||||
DEFINE_TWI_REG(MASTER_CTL, 0x14)
|
||||
DEFINE_TWI_REG(MASTER_STAT, 0x18)
|
||||
DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
|
||||
DEFINE_TWI_REG(INT_STAT, 0x20)
|
||||
DEFINE_TWI_REG(INT_MASK, 0x24)
|
||||
DEFINE_TWI_REG(FIFO_CTL, 0x28)
|
||||
DEFINE_TWI_REG(FIFO_STAT, 0x2C)
|
||||
DEFINE_TWI_REG(XMT_DATA8, 0x80)
|
||||
DEFINE_TWI_REG(XMT_DATA16, 0x84)
|
||||
DEFINE_TWI_REG(RCV_DATA8, 0x88)
|
||||
DEFINE_TWI_REG(RCV_DATA16, 0x8C)
|
||||
|
||||
static const u16 pin_req[2][3] = {
|
||||
{P_TWI0_SCL, P_TWI0_SDA, 0},
|
||||
{P_TWI1_SCL, P_TWI1_SDA, 0},
|
||||
};
|
||||
|
||||
static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||
unsigned short twi_int_status)
|
||||
{
|
||||
|
@ -99,7 +50,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
|||
*/
|
||||
else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | MDIR | RSTART);
|
||||
read_MASTER_CTL(iface) | MDIR);
|
||||
else if (iface->manual_stop)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
|
@ -107,10 +58,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
|||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | RSTART | MDIR);
|
||||
read_MASTER_CTL(iface) | MDIR);
|
||||
else
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
|
||||
read_MASTER_CTL(iface) & ~MDIR);
|
||||
}
|
||||
}
|
||||
if (twi_int_status & RCVSERV) {
|
||||
|
@ -130,17 +81,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
|||
}
|
||||
iface->transPtr++;
|
||||
iface->readNum--;
|
||||
} else if (iface->manual_stop) {
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
|
||||
}
|
||||
|
||||
if (iface->readNum == 0) {
|
||||
if (iface->manual_stop) {
|
||||
/* Temporary workaround to avoid possible bus stall -
|
||||
* Flush FIFO before issuing the STOP condition
|
||||
*/
|
||||
read_RCV_DATA16(iface);
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | RSTART | MDIR);
|
||||
else
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
|
||||
read_MASTER_CTL(iface) | STOP);
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) | MDIR);
|
||||
else
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~MDIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (twi_int_status & MERR) {
|
||||
|
@ -193,7 +152,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
|||
return;
|
||||
}
|
||||
if (twi_int_status & MCOMP) {
|
||||
if ((read_MASTER_CTL(iface) & MEN) == 0 &&
|
||||
if (twi_int_status & (XMTSERV | RCVSERV) &&
|
||||
(read_MASTER_CTL(iface) & MEN) == 0 &&
|
||||
(iface->cur_mode == TWI_I2C_MODE_REPEAT ||
|
||||
iface->cur_mode == TWI_I2C_MODE_COMBINED)) {
|
||||
iface->result = -1;
|
||||
|
@ -221,7 +181,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
|||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||
iface->cur_msg+1 < iface->msg_num) {
|
||||
iface->cur_msg + 1 < iface->msg_num) {
|
||||
iface->cur_msg++;
|
||||
iface->transPtr = iface->pmsg[iface->cur_msg].buf;
|
||||
iface->writeNum = iface->readNum =
|
||||
|
@ -241,27 +201,29 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
|||
}
|
||||
}
|
||||
|
||||
if (iface->pmsg[iface->cur_msg].len <= 255)
|
||||
write_MASTER_CTL(iface,
|
||||
if (iface->pmsg[iface->cur_msg].len <= 255) {
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) &
|
||||
(~(0xff << 6))) |
|
||||
(iface->pmsg[iface->cur_msg].len << 6));
|
||||
else {
|
||||
(iface->pmsg[iface->cur_msg].len << 6));
|
||||
iface->manual_stop = 0;
|
||||
} else {
|
||||
write_MASTER_CTL(iface,
|
||||
(read_MASTER_CTL(iface) |
|
||||
(0xff << 6)));
|
||||
iface->manual_stop = 1;
|
||||
}
|
||||
/* remove restart bit and enable master receive */
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
/* remove restart bit before last message */
|
||||
if (iface->cur_msg + 1 == iface->msg_num)
|
||||
write_MASTER_CTL(iface,
|
||||
read_MASTER_CTL(iface) & ~RSTART);
|
||||
} else {
|
||||
iface->result = 1;
|
||||
write_INT_MASK(iface, 0);
|
||||
write_MASTER_CTL(iface, 0);
|
||||
}
|
||||
complete(&iface->complete);
|
||||
}
|
||||
complete(&iface->complete);
|
||||
}
|
||||
|
||||
/* Interrupt handler */
|
||||
|
@ -298,8 +260,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
|
|||
if (!(read_CONTROL(iface) & TWI_ENA))
|
||||
return -ENXIO;
|
||||
|
||||
while (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
yield();
|
||||
if (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
return -EAGAIN;
|
||||
|
||||
iface->pmsg = msgs;
|
||||
iface->msg_num = num;
|
||||
|
@ -311,7 +273,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
iface->cur_mode = TWI_I2C_MODE_REPEAT;
|
||||
if (iface->msg_num > 1)
|
||||
iface->cur_mode = TWI_I2C_MODE_REPEAT;
|
||||
iface->manual_stop = 0;
|
||||
iface->transPtr = pmsg->buf;
|
||||
iface->writeNum = iface->readNum = pmsg->len;
|
||||
|
@ -356,6 +319,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
|
|||
|
||||
/* Master enable */
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
(iface->msg_num > 1 ? RSTART : 0) |
|
||||
((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
|
||||
SSYNC();
|
||||
|
@ -398,8 +362,8 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
|||
if (!(read_CONTROL(iface) & TWI_ENA))
|
||||
return -ENXIO;
|
||||
|
||||
while (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
yield();
|
||||
if (read_MASTER_STAT(iface) & BUSBUSY)
|
||||
return -EAGAIN;
|
||||
|
||||
iface->writeNum = 0;
|
||||
iface->readNum = 0;
|
||||
|
@ -520,7 +484,7 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
|||
else
|
||||
write_MASTER_CTL(iface, 0x1 << 6);
|
||||
/* Master enable */
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
|
||||
write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | RSTART |
|
||||
((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
|
||||
break;
|
||||
default:
|
||||
|
@ -611,9 +575,9 @@ static struct i2c_algorithm bfin_twi_algorithm = {
|
|||
.functionality = bfin_twi_functionality,
|
||||
};
|
||||
|
||||
static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int i2c_bfin_twi_suspend(struct device *dev)
|
||||
{
|
||||
struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
|
||||
struct bfin_twi_iface *iface = dev_get_drvdata(dev);
|
||||
|
||||
iface->saved_clkdiv = read_CLKDIV(iface);
|
||||
iface->saved_control = read_CONTROL(iface);
|
||||
|
@ -626,14 +590,14 @@ static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_bfin_twi_resume(struct platform_device *pdev)
|
||||
static int i2c_bfin_twi_resume(struct device *dev)
|
||||
{
|
||||
struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
|
||||
struct bfin_twi_iface *iface = dev_get_drvdata(dev);
|
||||
|
||||
int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
|
||||
0, pdev->name, iface);
|
||||
0, to_platform_device(dev)->name, iface);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
|
||||
dev_err(dev, "Can't get IRQ %d !\n", iface->irq);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -646,6 +610,9 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(i2c_bfin_twi_pm,
|
||||
i2c_bfin_twi_suspend, i2c_bfin_twi_resume);
|
||||
|
||||
static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_twi_iface *iface;
|
||||
|
@ -695,7 +662,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
|||
p_adap->timeout = 5 * HZ;
|
||||
p_adap->retries = 3;
|
||||
|
||||
rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
|
||||
rc = peripheral_request_list((unsigned short *)pdev->dev.platform_data,
|
||||
"i2c-bfin-twi");
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't setup pin mux!\n");
|
||||
goto out_error_pin_mux;
|
||||
|
@ -742,7 +710,7 @@ out_error_add_adapter:
|
|||
free_irq(iface->irq, iface);
|
||||
out_error_req_irq:
|
||||
out_error_no_irq:
|
||||
peripheral_free_list(pin_req[pdev->id]);
|
||||
peripheral_free_list((unsigned short *)pdev->dev.platform_data);
|
||||
out_error_pin_mux:
|
||||
iounmap(iface->regs_base);
|
||||
out_error_ioremap:
|
||||
|
@ -760,7 +728,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
|
|||
|
||||
i2c_del_adapter(&(iface->adap));
|
||||
free_irq(iface->irq, iface);
|
||||
peripheral_free_list(pin_req[pdev->id]);
|
||||
peripheral_free_list((unsigned short *)pdev->dev.platform_data);
|
||||
iounmap(iface->regs_base);
|
||||
kfree(iface);
|
||||
|
||||
|
@ -770,11 +738,10 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
|
|||
static struct platform_driver i2c_bfin_twi_driver = {
|
||||
.probe = i2c_bfin_twi_probe,
|
||||
.remove = i2c_bfin_twi_remove,
|
||||
.suspend = i2c_bfin_twi_suspend,
|
||||
.resume = i2c_bfin_twi_resume,
|
||||
.driver = {
|
||||
.name = "i2c-bfin-twi",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &i2c_bfin_twi_pm,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -117,10 +117,8 @@ static u16 __initdata i2c_clk_div[50][2] = {
|
|||
|
||||
struct imx_i2c_struct {
|
||||
struct i2c_adapter adapter;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
wait_queue_head_t queue;
|
||||
unsigned long i2csr;
|
||||
unsigned int disable_delay;
|
||||
|
@ -472,9 +470,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct pinctrl *pinctrl;
|
||||
void __iomem *base;
|
||||
resource_size_t res_size;
|
||||
int irq, bitrate;
|
||||
int ret;
|
||||
int irq, ret;
|
||||
u32 bitrate;
|
||||
|
||||
dev_dbg(&pdev->dev, "<%s>\n", __func__);
|
||||
|
||||
|
@ -489,25 +486,15 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
res_size = resource_size(res);
|
||||
|
||||
if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
|
||||
dev_err(&pdev->dev, "request_mem_region failed\n");
|
||||
base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!base)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
base = ioremap(res->start, res_size);
|
||||
if (!base) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = -EIO;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
|
||||
i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct),
|
||||
GFP_KERNEL);
|
||||
if (!i2c_imx) {
|
||||
dev_err(&pdev->dev, "can't allocate interface\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail2;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Setup i2c_imx driver structure */
|
||||
|
@ -517,29 +504,27 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
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;
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl)) {
|
||||
ret = PTR_ERR(pinctrl);
|
||||
goto fail3;
|
||||
dev_err(&pdev->dev, "can't get/select pinctrl\n");
|
||||
return PTR_ERR(pinctrl);
|
||||
}
|
||||
|
||||
/* Get I2C clock */
|
||||
i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
|
||||
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c_imx->clk)) {
|
||||
ret = PTR_ERR(i2c_imx->clk);
|
||||
dev_err(&pdev->dev, "can't get I2C clock\n");
|
||||
goto fail3;
|
||||
return PTR_ERR(i2c_imx->clk);
|
||||
}
|
||||
|
||||
/* Request IRQ */
|
||||
ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
|
||||
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
|
||||
pdev->name, i2c_imx);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq);
|
||||
goto fail4;
|
||||
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Init queue */
|
||||
|
@ -564,7 +549,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "registration failed\n");
|
||||
goto fail5;
|
||||
return ret;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&i2c_imx->adapter);
|
||||
|
@ -572,28 +557,16 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
|
|||
/* Set up platform driver data */
|
||||
platform_set_drvdata(pdev, i2c_imx);
|
||||
|
||||
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",
|
||||
i2c_imx->res->start, i2c_imx->res->end);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n",
|
||||
res_size, i2c_imx->res->start);
|
||||
res->start, res->end);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x\n",
|
||||
resource_size(res), res->start);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
|
||||
i2c_imx->adapter.name);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
|
||||
|
||||
return 0; /* Return OK */
|
||||
|
||||
fail5:
|
||||
free_irq(i2c_imx->irq, i2c_imx);
|
||||
fail4:
|
||||
clk_put(i2c_imx->clk);
|
||||
fail3:
|
||||
kfree(i2c_imx);
|
||||
fail2:
|
||||
iounmap(base);
|
||||
fail1:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
return ret; /* Return error number */
|
||||
}
|
||||
|
||||
static int __exit i2c_imx_remove(struct platform_device *pdev)
|
||||
|
@ -605,20 +578,12 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
|
|||
i2c_del_adapter(&i2c_imx->adapter);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
/* free interrupt */
|
||||
free_irq(i2c_imx->irq, i2c_imx);
|
||||
|
||||
/* setup chip registers to defaults */
|
||||
writeb(0, i2c_imx->base + IMX_I2C_IADR);
|
||||
writeb(0, i2c_imx->base + IMX_I2C_IFDR);
|
||||
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
|
||||
writeb(0, i2c_imx->base + IMX_I2C_I2SR);
|
||||
|
||||
clk_put(i2c_imx->clk);
|
||||
|
||||
iounmap(i2c_imx->base);
|
||||
release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
|
||||
kfree(i2c_imx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
#include <linux/mv643xx_i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
/* Register defines */
|
||||
#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00
|
||||
|
@ -98,6 +103,9 @@ struct mv64xxx_i2c_data {
|
|||
int rc;
|
||||
u32 freq_m;
|
||||
u32 freq_n;
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
struct clk *clk;
|
||||
#endif
|
||||
wait_queue_head_t waitq;
|
||||
spinlock_t lock;
|
||||
struct i2c_msg *msg;
|
||||
|
@ -521,6 +529,82 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
|
|||
drv_data->reg_base_p = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int __devinit
|
||||
mv64xxx_calc_freq(const int tclk, const int n, const int m)
|
||||
{
|
||||
return tclk / (10 * (m + 1) * (2 << n));
|
||||
}
|
||||
|
||||
static bool __devinit
|
||||
mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
|
||||
u32 *best_m)
|
||||
{
|
||||
int freq, delta, best_delta = INT_MAX;
|
||||
int m, n;
|
||||
|
||||
for (n = 0; n <= 7; n++)
|
||||
for (m = 0; m <= 15; m++) {
|
||||
freq = mv64xxx_calc_freq(tclk, n, m);
|
||||
delta = req_freq - freq;
|
||||
if (delta >= 0 && delta < best_delta) {
|
||||
*best_m = m;
|
||||
*best_n = n;
|
||||
best_delta = delta;
|
||||
}
|
||||
if (best_delta == 0)
|
||||
return true;
|
||||
}
|
||||
if (best_delta == INT_MAX)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
struct device_node *np)
|
||||
{
|
||||
u32 bus_freq, tclk;
|
||||
int rc = 0;
|
||||
|
||||
/* CLK is mandatory when using DT to describe the i2c bus. We
|
||||
* need to know tclk in order to calculate bus clock
|
||||
* factors.
|
||||
*/
|
||||
#if !defined(CONFIG_HAVE_CLK)
|
||||
/* Have OF but no CLK */
|
||||
return -ENODEV;
|
||||
#else
|
||||
if (IS_ERR(drv_data->clk)) {
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
tclk = clk_get_rate(drv_data->clk);
|
||||
of_property_read_u32(np, "clock-frequency", &bus_freq);
|
||||
if (!mv64xxx_find_baud_factors(bus_freq, tclk,
|
||||
&drv_data->freq_n, &drv_data->freq_m)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
drv_data->irq = irq_of_parse_and_map(np, 0);
|
||||
|
||||
/* Its not yet defined how timeouts will be specified in device tree.
|
||||
* So hard code the value to 1 second.
|
||||
*/
|
||||
drv_data->adapter.timeout = HZ;
|
||||
out:
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
static int __devinit
|
||||
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
struct device_node *np)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int __devinit
|
||||
mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
{
|
||||
|
@ -528,7 +612,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
|||
struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data;
|
||||
int rc;
|
||||
|
||||
if ((pd->id != 0) || !pdata)
|
||||
if ((!pdata && !pd->dev.of_node))
|
||||
return -ENODEV;
|
||||
|
||||
drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
|
||||
|
@ -546,19 +630,35 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
|||
init_waitqueue_head(&drv_data->waitq);
|
||||
spin_lock_init(&drv_data->lock);
|
||||
|
||||
drv_data->freq_m = pdata->freq_m;
|
||||
drv_data->freq_n = pdata->freq_n;
|
||||
drv_data->irq = platform_get_irq(pd, 0);
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
drv_data->clk = clk_get(&pd->dev, NULL);
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_prepare(drv_data->clk);
|
||||
clk_enable(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
if (pdata) {
|
||||
drv_data->freq_m = pdata->freq_m;
|
||||
drv_data->freq_n = pdata->freq_n;
|
||||
drv_data->irq = platform_get_irq(pd, 0);
|
||||
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
|
||||
} else if (pd->dev.of_node) {
|
||||
rc = mv64xxx_of_config(drv_data, pd->dev.of_node);
|
||||
if (rc)
|
||||
goto exit_unmap_regs;
|
||||
}
|
||||
if (drv_data->irq < 0) {
|
||||
rc = -ENXIO;
|
||||
goto exit_unmap_regs;
|
||||
}
|
||||
|
||||
drv_data->adapter.dev.parent = &pd->dev;
|
||||
drv_data->adapter.algo = &mv64xxx_i2c_algo;
|
||||
drv_data->adapter.owner = THIS_MODULE;
|
||||
drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
|
||||
drv_data->adapter.nr = pd->id;
|
||||
drv_data->adapter.dev.of_node = pd->dev.of_node;
|
||||
platform_set_drvdata(pd, drv_data);
|
||||
i2c_set_adapdata(&drv_data->adapter, drv_data);
|
||||
|
||||
|
@ -577,11 +677,20 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
|||
goto exit_free_irq;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&drv_data->adapter);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_irq:
|
||||
free_irq(drv_data->irq, drv_data);
|
||||
exit_unmap_regs:
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_disable(drv_data->clk);
|
||||
clk_unprepare(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
mv64xxx_i2c_unmap_regs(drv_data);
|
||||
exit_kfree:
|
||||
kfree(drv_data);
|
||||
|
@ -597,17 +706,31 @@ mv64xxx_i2c_remove(struct platform_device *dev)
|
|||
rc = i2c_del_adapter(&drv_data->adapter);
|
||||
free_irq(drv_data->irq, drv_data);
|
||||
mv64xxx_i2c_unmap_regs(drv_data);
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_disable(drv_data->clk);
|
||||
clk_unprepare(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
kfree(drv_data);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = {
|
||||
{ .compatible = "marvell,mv64xxx-i2c", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
|
||||
|
||||
static struct platform_driver mv64xxx_i2c_driver = {
|
||||
.probe = mv64xxx_i2c_probe,
|
||||
.remove = __devexit_p(mv64xxx_i2c_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = MV64XXX_I2C_CTLR_NAME,
|
||||
.of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@
|
|||
#define MXS_I2C_CTRL0_DIRECTION 0x00010000
|
||||
#define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF)
|
||||
|
||||
#define MXS_I2C_TIMING0 (0x10)
|
||||
#define MXS_I2C_TIMING1 (0x20)
|
||||
#define MXS_I2C_TIMING2 (0x30)
|
||||
|
||||
#define MXS_I2C_CTRL1 (0x40)
|
||||
#define MXS_I2C_CTRL1_SET (0x44)
|
||||
#define MXS_I2C_CTRL1_CLR (0x48)
|
||||
|
@ -97,6 +101,35 @@
|
|||
#define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
|
||||
MXS_I2C_CTRL0_MASTER_MODE)
|
||||
|
||||
struct mxs_i2c_speed_config {
|
||||
uint32_t timing0;
|
||||
uint32_t timing1;
|
||||
uint32_t timing2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Timing values for the default 24MHz clock supplied into the i2c block.
|
||||
*
|
||||
* The bus can operate at 95kHz or at 400kHz with the following timing
|
||||
* register configurations. The 100kHz mode isn't present because it's
|
||||
* values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode
|
||||
* shall be close enough replacement. Therefore when the bus is configured
|
||||
* for 100kHz operation, 95kHz timing settings are actually loaded.
|
||||
*
|
||||
* For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4].
|
||||
*/
|
||||
static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
|
||||
.timing0 = 0x00780030,
|
||||
.timing1 = 0x00800030,
|
||||
.timing2 = 0x00300030,
|
||||
};
|
||||
|
||||
static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
|
||||
.timing0 = 0x000f0007,
|
||||
.timing1 = 0x001f000f,
|
||||
.timing2 = 0x00300030,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mxs_i2c_dev - per device, private MXS-I2C data
|
||||
*
|
||||
|
@ -112,11 +145,17 @@ struct mxs_i2c_dev {
|
|||
struct completion cmd_complete;
|
||||
u32 cmd_err;
|
||||
struct i2c_adapter adapter;
|
||||
const struct mxs_i2c_speed_config *speed;
|
||||
};
|
||||
|
||||
static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
|
||||
{
|
||||
stmp_reset_block(i2c->regs);
|
||||
|
||||
writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0);
|
||||
writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1);
|
||||
writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
|
||||
|
||||
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
|
||||
writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
|
||||
i2c->regs + MXS_I2C_QUEUECTRL_SET);
|
||||
|
@ -193,7 +232,7 @@ static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
|
|||
|
||||
static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
|
||||
{
|
||||
u32 data;
|
||||
u32 uninitialized_var(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
|
@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = {
|
|||
.functionality = mxs_i2c_func,
|
||||
};
|
||||
|
||||
static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
|
||||
{
|
||||
uint32_t speed;
|
||||
struct device *dev = i2c->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
int ret;
|
||||
|
||||
if (!node)
|
||||
return -EINVAL;
|
||||
|
||||
i2c->speed = &mxs_i2c_95kHz_config;
|
||||
ret = of_property_read_u32(node, "clock-frequency", &speed);
|
||||
if (ret)
|
||||
dev_warn(dev, "No I2C speed selected, using 100kHz\n");
|
||||
else if (speed == 400000)
|
||||
i2c->speed = &mxs_i2c_400kHz_config;
|
||||
else if (speed != 100000)
|
||||
dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit mxs_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
|
||||
i2c->dev = dev;
|
||||
|
||||
err = mxs_i2c_get_ofdata(i2c);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
/* Do reset to enforce correct startup after pinmuxing */
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -23,8 +24,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
#include <linux/platform_data/i2c-nomadik.h>
|
||||
|
||||
#define DRIVER_NAME "nmk-i2c"
|
||||
|
||||
|
@ -136,7 +136,7 @@ struct i2c_nmk_client {
|
|||
|
||||
/**
|
||||
* struct nmk_i2c_dev - private data structure of the controller.
|
||||
* @pdev: parent platform device.
|
||||
* @adev: parent amba device.
|
||||
* @adap: corresponding I2C adapter.
|
||||
* @irq: interrupt line for the controller.
|
||||
* @virtbase: virtual io memory area.
|
||||
|
@ -150,7 +150,7 @@ struct i2c_nmk_client {
|
|||
* @busy: Busy doing transfer.
|
||||
*/
|
||||
struct nmk_i2c_dev {
|
||||
struct platform_device *pdev;
|
||||
struct amba_device *adev;
|
||||
struct i2c_adapter adap;
|
||||
int irq;
|
||||
void __iomem *virtbase;
|
||||
|
@ -217,7 +217,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"flushing operation timed out giving up after %d attempts",
|
||||
LOOP_ATTEMPTS);
|
||||
|
||||
|
@ -276,15 +276,32 @@ exit:
|
|||
/**
|
||||
* load_i2c_mcr_reg() - load the MCR register
|
||||
* @dev: private data of controller
|
||||
* @flags: message flags
|
||||
*/
|
||||
static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev)
|
||||
static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags)
|
||||
{
|
||||
u32 mcr = 0;
|
||||
unsigned short slave_adr_3msb_bits;
|
||||
|
||||
/* 7-bit address transaction */
|
||||
mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
|
||||
mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
|
||||
|
||||
if (unlikely(flags & I2C_M_TEN)) {
|
||||
/* 10-bit address transaction */
|
||||
mcr |= GEN_MASK(2, I2C_MCR_AM, 12);
|
||||
/*
|
||||
* Get the top 3 bits.
|
||||
* EA10 represents extended address in MCR. This includes
|
||||
* the extension (MSB bits) of the 7 bit address loaded
|
||||
* in A7
|
||||
*/
|
||||
slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7;
|
||||
|
||||
mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8);
|
||||
} else {
|
||||
/* 7-bit address transaction */
|
||||
mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
|
||||
}
|
||||
|
||||
/* start byte procedure not applied */
|
||||
mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
|
||||
|
||||
|
@ -364,7 +381,7 @@ 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,
|
||||
dev_err(&dev->adev->dev,
|
||||
"do not support this mode defaulting to std. mode\n");
|
||||
brcr2 = i2c_clk/(100000 * 2) & 0xffff;
|
||||
writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
|
||||
|
@ -381,19 +398,20 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
|
|||
/**
|
||||
* read_i2c() - Read from I2C client device
|
||||
* @dev: private data of I2C Driver
|
||||
* @flags: message flags
|
||||
*
|
||||
* This function reads from i2c client device when controller is in
|
||||
* master mode. There is a completion timeout. If there is no transfer
|
||||
* before timeout error is returned.
|
||||
*/
|
||||
static int read_i2c(struct nmk_i2c_dev *dev)
|
||||
static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
|
||||
{
|
||||
u32 status = 0;
|
||||
u32 mcr;
|
||||
u32 irq_mask = 0;
|
||||
int timeout;
|
||||
|
||||
mcr = load_i2c_mcr_reg(dev);
|
||||
mcr = load_i2c_mcr_reg(dev, flags);
|
||||
writel(mcr, dev->virtbase + I2C_MCR);
|
||||
|
||||
/* load the current CR value */
|
||||
|
@ -423,7 +441,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
|
|||
&dev->xfer_complete, dev->adap.timeout);
|
||||
|
||||
if (timeout < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"wait_for_completion_timeout "
|
||||
"returned %d waiting for event\n", timeout);
|
||||
status = timeout;
|
||||
|
@ -431,7 +449,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
|
|||
|
||||
if (timeout == 0) {
|
||||
/* Controller timed out */
|
||||
dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
|
||||
dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n",
|
||||
dev->cli.slave_adr);
|
||||
status = -ETIMEDOUT;
|
||||
}
|
||||
|
@ -459,17 +477,18 @@ static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
|
|||
/**
|
||||
* write_i2c() - Write data to I2C client.
|
||||
* @dev: private data of I2C Driver
|
||||
* @flags: message flags
|
||||
*
|
||||
* This function writes data to I2C client
|
||||
*/
|
||||
static int write_i2c(struct nmk_i2c_dev *dev)
|
||||
static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
|
||||
{
|
||||
u32 status = 0;
|
||||
u32 mcr;
|
||||
u32 irq_mask = 0;
|
||||
int timeout;
|
||||
|
||||
mcr = load_i2c_mcr_reg(dev);
|
||||
mcr = load_i2c_mcr_reg(dev, flags);
|
||||
|
||||
writel(mcr, dev->virtbase + I2C_MCR);
|
||||
|
||||
|
@ -510,7 +529,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
|
|||
&dev->xfer_complete, dev->adap.timeout);
|
||||
|
||||
if (timeout < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"wait_for_completion_timeout "
|
||||
"returned %d waiting for event\n", timeout);
|
||||
status = timeout;
|
||||
|
@ -518,7 +537,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
|
|||
|
||||
if (timeout == 0) {
|
||||
/* Controller timed out */
|
||||
dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
|
||||
dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n",
|
||||
dev->cli.slave_adr);
|
||||
status = -ETIMEDOUT;
|
||||
}
|
||||
|
@ -538,11 +557,11 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
|
|||
if (flags & I2C_M_RD) {
|
||||
/* read operation */
|
||||
dev->cli.operation = I2C_READ;
|
||||
status = read_i2c(dev);
|
||||
status = read_i2c(dev, flags);
|
||||
} else {
|
||||
/* write operation */
|
||||
dev->cli.operation = I2C_WRITE;
|
||||
status = write_i2c(dev);
|
||||
status = write_i2c(dev, flags);
|
||||
}
|
||||
|
||||
if (status || (dev->result)) {
|
||||
|
@ -557,7 +576,7 @@ 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",
|
||||
dev_err(&dev->adev->dev, "%s\n",
|
||||
cause >= ARRAY_SIZE(abort_causes) ?
|
||||
"unknown reason" :
|
||||
abort_causes[cause]);
|
||||
|
@ -630,7 +649,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
|
||||
if (dev->regulator)
|
||||
regulator_enable(dev->regulator);
|
||||
pm_runtime_get_sync(&dev->pdev->dev);
|
||||
pm_runtime_get_sync(&dev->adev->dev);
|
||||
|
||||
clk_enable(dev->clk);
|
||||
|
||||
|
@ -644,13 +663,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
setup_i2c_controller(dev);
|
||||
|
||||
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");
|
||||
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
dev->cli.slave_adr = msgs[i].addr;
|
||||
dev->cli.buffer = msgs[i].buf;
|
||||
dev->cli.count = msgs[i].len;
|
||||
|
@ -667,7 +679,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
|
||||
out:
|
||||
clk_disable(dev->clk);
|
||||
pm_runtime_put_sync(&dev->pdev->dev);
|
||||
pm_runtime_put_sync(&dev->adev->dev);
|
||||
if (dev->regulator)
|
||||
regulator_disable(dev->regulator);
|
||||
|
||||
|
@ -790,7 +802,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
|||
|
||||
if (dev->cli.count) {
|
||||
dev->result = -EIO;
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&dev->adev->dev,
|
||||
"%lu bytes still remain to be xfered\n",
|
||||
dev->cli.count);
|
||||
(void) init_hw(dev);
|
||||
|
@ -834,7 +846,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
|||
dev->result = -EIO;
|
||||
(void) init_hw(dev);
|
||||
|
||||
dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
|
||||
dev_err(&dev->adev->dev, "Tx Fifo Over run\n");
|
||||
complete(&dev->xfer_complete);
|
||||
|
||||
break;
|
||||
|
@ -847,10 +859,10 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
|||
case I2C_IT_RFSE:
|
||||
case I2C_IT_WTSR:
|
||||
case I2C_IT_STD:
|
||||
dev_err(&dev->pdev->dev, "unhandled Interrupt\n");
|
||||
dev_err(&dev->adev->dev, "unhandled Interrupt\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(&dev->pdev->dev, "spurious Interrupt..\n");
|
||||
dev_err(&dev->adev->dev, "spurious Interrupt..\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -861,8 +873,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
|
|||
#ifdef CONFIG_PM
|
||||
static int nmk_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
|
||||
struct amba_device *adev = to_amba_device(dev);
|
||||
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
|
||||
|
||||
if (nmk_i2c->busy)
|
||||
return -EBUSY;
|
||||
|
@ -891,7 +903,7 @@ static const struct dev_pm_ops nmk_i2c_pm = {
|
|||
|
||||
static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm nmk_i2c_algo = {
|
||||
|
@ -899,78 +911,69 @@ static const struct i2c_algorithm nmk_i2c_algo = {
|
|||
.functionality = nmk_i2c_functionality
|
||||
};
|
||||
|
||||
static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
||||
static atomic_t adapter_id = ATOMIC_INIT(0);
|
||||
|
||||
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
{
|
||||
int ret = 0;
|
||||
struct resource *res;
|
||||
struct nmk_i2c_controller *pdata =
|
||||
pdev->dev.platform_data;
|
||||
adev->dev.platform_data;
|
||||
struct nmk_i2c_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
|
||||
if (!pdata) {
|
||||
dev_warn(&adev->dev, "no platform data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
dev_err(&pdev->dev, "cannot allocate memory\n");
|
||||
dev_err(&adev->dev, "cannot allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_no_mem;
|
||||
}
|
||||
dev->busy = false;
|
||||
dev->pdev = pdev;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
dev->adev = adev;
|
||||
amba_set_drvdata(adev, dev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto err_no_resource;
|
||||
}
|
||||
|
||||
if (request_mem_region(res->start, resource_size(res),
|
||||
DRIVER_NAME "I/O region") == NULL) {
|
||||
ret = -EBUSY;
|
||||
goto err_no_region;
|
||||
}
|
||||
|
||||
dev->virtbase = ioremap(res->start, resource_size(res));
|
||||
dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
|
||||
if (!dev->virtbase) {
|
||||
ret = -ENOMEM;
|
||||
goto err_no_ioremap;
|
||||
}
|
||||
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
dev->irq = adev->irq[0];
|
||||
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);
|
||||
dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
dev->regulator = regulator_get(&pdev->dev, "v-i2c");
|
||||
dev->regulator = regulator_get(&adev->dev, "v-i2c");
|
||||
if (IS_ERR(dev->regulator)) {
|
||||
dev_warn(&pdev->dev, "could not get i2c regulator\n");
|
||||
dev_warn(&adev->dev, "could not get i2c regulator\n");
|
||||
dev->regulator = NULL;
|
||||
}
|
||||
|
||||
pm_suspend_ignore_children(&pdev->dev, true);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_suspend_ignore_children(&adev->dev, true);
|
||||
|
||||
dev->clk = clk_get(&pdev->dev, NULL);
|
||||
dev->clk = clk_get(&adev->dev, NULL);
|
||||
if (IS_ERR(dev->clk)) {
|
||||
dev_err(&pdev->dev, "could not get i2c clock\n");
|
||||
dev_err(&adev->dev, "could not get i2c clock\n");
|
||||
ret = PTR_ERR(dev->clk);
|
||||
goto err_no_clk;
|
||||
}
|
||||
|
||||
adap = &dev->adap;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.parent = &adev->dev;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adap->algo = &nmk_i2c_algo;
|
||||
adap->timeout = msecs_to_jiffies(pdata->timeout);
|
||||
adap->nr = atomic_read(&adapter_id);
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
|
||||
|
||||
/* fetch the controller id */
|
||||
adap->nr = pdev->id;
|
||||
"Nomadik I2C%d at %pR", adap->nr, &adev->res);
|
||||
atomic_inc(&adapter_id);
|
||||
|
||||
/* fetch the controller configuration from machine */
|
||||
dev->cfg.clk_freq = pdata->clk_freq;
|
||||
|
@ -981,16 +984,18 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
||||
dev_info(&pdev->dev,
|
||||
dev_info(&adev->dev,
|
||||
"initialize %s on virtual base %p\n",
|
||||
adap->name, dev->virtbase);
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add adapter\n");
|
||||
dev_err(&adev->dev, "failed to add adapter\n");
|
||||
goto err_add_adap;
|
||||
}
|
||||
|
||||
pm_runtime_put(&adev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_adap:
|
||||
|
@ -998,25 +1003,21 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
|
|||
err_no_clk:
|
||||
if (dev->regulator)
|
||||
regulator_put(dev->regulator);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
free_irq(dev->irq, dev);
|
||||
err_irq:
|
||||
iounmap(dev->virtbase);
|
||||
err_no_ioremap:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err_no_region:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
err_no_resource:
|
||||
amba_set_drvdata(adev, NULL);
|
||||
kfree(dev);
|
||||
err_no_mem:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit nmk_i2c_remove(struct platform_device *pdev)
|
||||
static int nmk_i2c_remove(struct amba_device *adev)
|
||||
{
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct resource *res = &adev->res;
|
||||
struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
|
||||
|
||||
i2c_del_adapter(&dev->adap);
|
||||
flush_i2c_fifo(dev);
|
||||
|
@ -1031,31 +1032,46 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
|
|||
clk_put(dev->clk);
|
||||
if (dev->regulator)
|
||||
regulator_put(dev->regulator);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
pm_runtime_disable(&adev->dev);
|
||||
amba_set_drvdata(adev, NULL);
|
||||
kfree(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver nmk_i2c_driver = {
|
||||
.driver = {
|
||||
static struct amba_id nmk_i2c_ids[] = {
|
||||
{
|
||||
.id = 0x00180024,
|
||||
.mask = 0x00ffffff,
|
||||
},
|
||||
{
|
||||
.id = 0x00380024,
|
||||
.mask = 0x00ffffff,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, nmk_i2c_ids);
|
||||
|
||||
static struct amba_driver nmk_i2c_driver = {
|
||||
.drv = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.pm = &nmk_i2c_pm,
|
||||
},
|
||||
.id_table = nmk_i2c_ids,
|
||||
.probe = nmk_i2c_probe,
|
||||
.remove = __devexit_p(nmk_i2c_remove),
|
||||
.remove = nmk_i2c_remove,
|
||||
};
|
||||
|
||||
static int __init nmk_i2c_init(void)
|
||||
{
|
||||
return platform_driver_register(&nmk_i2c_driver);
|
||||
return amba_driver_register(&nmk_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit nmk_i2c_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&nmk_i2c_driver);
|
||||
amba_driver_unregister(&nmk_i2c_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(nmk_i2c_init);
|
||||
|
@ -1064,4 +1080,3 @@ module_exit(nmk_i2c_exit);
|
|||
MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
|
||||
MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
|
|
|
@ -10,40 +10,9 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Device tree configuration:
|
||||
*
|
||||
* Required properties:
|
||||
* - compatible : "opencores,i2c-ocores"
|
||||
* - reg : bus address start and address range size of device
|
||||
* - interrupts : interrupt number
|
||||
* - regstep : size of device registers in bytes
|
||||
* - clock-frequency : frequency of bus clock in Hz
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* i2c0: ocores@a0000000 {
|
||||
* compatible = "opencores,i2c-ocores";
|
||||
* reg = <0xa0000000 0x8>;
|
||||
* interrupts = <10>;
|
||||
*
|
||||
* regstep = <1>;
|
||||
* clock-frequency = <20000000>;
|
||||
*
|
||||
* -- Devices connected on this I2C bus get
|
||||
* -- defined here; address- and size-cells
|
||||
* -- apply to these child devices
|
||||
*
|
||||
* #address-cells = <1>;
|
||||
* #size-cells = <0>;
|
||||
*
|
||||
* dummy@60 {
|
||||
* compatible = "dummy";
|
||||
* reg = <60>;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* This driver can be used from the device tree, see
|
||||
* Documentation/devicetree/bindings/i2c/ocore-i2c.txt
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -56,10 +25,12 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
struct ocores_i2c {
|
||||
void __iomem *base;
|
||||
int regstep;
|
||||
u32 reg_shift;
|
||||
u32 reg_io_width;
|
||||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_msg *msg;
|
||||
|
@ -102,12 +73,22 @@ struct ocores_i2c {
|
|||
|
||||
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
|
||||
{
|
||||
iowrite8(value, i2c->base + reg * i2c->regstep);
|
||||
if (i2c->reg_io_width == 4)
|
||||
iowrite32(value, i2c->base + (reg << i2c->reg_shift));
|
||||
else if (i2c->reg_io_width == 2)
|
||||
iowrite16(value, i2c->base + (reg << i2c->reg_shift));
|
||||
else
|
||||
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
|
||||
}
|
||||
|
||||
static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
|
||||
{
|
||||
return ioread8(i2c->base + reg * i2c->regstep);
|
||||
if (i2c->reg_io_width == 4)
|
||||
return ioread32(i2c->base + (reg << i2c->reg_shift));
|
||||
else if (i2c->reg_io_width == 2)
|
||||
return ioread16(i2c->base + (reg << i2c->reg_shift));
|
||||
else
|
||||
return ioread8(i2c->base + (reg << i2c->reg_shift));
|
||||
}
|
||||
|
||||
static void ocores_process(struct ocores_i2c *i2c)
|
||||
|
@ -247,26 +228,35 @@ static struct i2c_adapter ocores_adapter = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int ocores_i2c_of_probe(struct platform_device* pdev,
|
||||
struct ocores_i2c* i2c)
|
||||
static int ocores_i2c_of_probe(struct platform_device *pdev,
|
||||
struct ocores_i2c *i2c)
|
||||
{
|
||||
const __be32* val;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 val;
|
||||
|
||||
val = of_get_property(pdev->dev.of_node, "regstep", NULL);
|
||||
if (!val) {
|
||||
dev_err(&pdev->dev, "Missing required parameter 'regstep'");
|
||||
return -ENODEV;
|
||||
if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
|
||||
/* no 'reg-shift', check for deprecated 'regstep' */
|
||||
if (!of_property_read_u32(np, "regstep", &val)) {
|
||||
if (!is_power_of_2(val)) {
|
||||
dev_err(&pdev->dev, "invalid regstep %d\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
i2c->reg_shift = ilog2(val);
|
||||
dev_warn(&pdev->dev,
|
||||
"regstep property deprecated, use reg-shift\n");
|
||||
}
|
||||
}
|
||||
i2c->regstep = be32_to_cpup(val);
|
||||
|
||||
val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL);
|
||||
if (!val) {
|
||||
if (of_property_read_u32(np, "clock-frequency", &val)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Missing required parameter 'clock-frequency'");
|
||||
"Missing required parameter 'clock-frequency'\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
i2c->clock_khz = be32_to_cpup(val) / 1000;
|
||||
i2c->clock_khz = val / 1000;
|
||||
|
||||
of_property_read_u32(pdev->dev.of_node, "reg-io-width",
|
||||
&i2c->reg_io_width);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -308,7 +298,8 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata) {
|
||||
i2c->regstep = pdata->regstep;
|
||||
i2c->reg_shift = pdata->reg_shift;
|
||||
i2c->reg_io_width = pdata->reg_io_width;
|
||||
i2c->clock_khz = pdata->clock_khz;
|
||||
} else {
|
||||
ret = ocores_i2c_of_probe(pdev, i2c);
|
||||
|
@ -316,6 +307,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (i2c->reg_io_width == 0)
|
||||
i2c->reg_io_width = 1; /* Set to default value */
|
||||
|
||||
ocores_init(i2c);
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
@ -351,7 +345,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit ocores_i2c_remove(struct platform_device* pdev)
|
||||
static int __devexit ocores_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
|
@ -367,9 +361,9 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int ocores_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct ocores_i2c *i2c = dev_get_drvdata(dev);
|
||||
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
|
||||
|
||||
/* make sure the device is disabled */
|
||||
|
@ -378,17 +372,19 @@ static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ocores_i2c_resume(struct platform_device *pdev)
|
||||
static int ocores_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct ocores_i2c *i2c = dev_get_drvdata(dev);
|
||||
|
||||
ocores_init(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
|
||||
#define OCORES_I2C_PM (&ocores_i2c_pm)
|
||||
#else
|
||||
#define ocores_i2c_suspend NULL
|
||||
#define ocores_i2c_resume NULL
|
||||
#define OCORES_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static struct of_device_id ocores_i2c_match[] = {
|
||||
|
@ -400,12 +396,11 @@ MODULE_DEVICE_TABLE(of, ocores_i2c_match);
|
|||
static struct platform_driver ocores_i2c_driver = {
|
||||
.probe = ocores_i2c_probe,
|
||||
.remove = __devexit_p(ocores_i2c_remove),
|
||||
.suspend = ocores_i2c_suspend,
|
||||
.resume = ocores_i2c_resume,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ocores-i2c",
|
||||
.of_match_table = ocores_i2c_match,
|
||||
.pm = OCORES_I2C_PM,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@
|
|||
|
||||
/* 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_3530_4430 0x40
|
||||
#define OMAP_I2C_REV_ON_3430_3530 0x3C
|
||||
#define OMAP_I2C_REV_ON_3630_4430 0x40
|
||||
|
||||
/* timeout waiting for the controller to respond */
|
||||
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
@ -173,7 +173,7 @@ enum {
|
|||
|
||||
/* Errata definitions */
|
||||
#define I2C_OMAP_ERRATA_I207 (1 << 0)
|
||||
#define I2C_OMAP3_1P153 (1 << 1)
|
||||
#define I2C_OMAP_ERRATA_I462 (1 << 1)
|
||||
|
||||
struct omap_i2c_dev {
|
||||
struct device *dev;
|
||||
|
@ -269,47 +269,6 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
|
|||
(i2c_dev->regs[reg] << i2c_dev->reg_shift));
|
||||
}
|
||||
|
||||
static void omap_i2c_unidle(struct omap_i2c_dev *dev)
|
||||
{
|
||||
if (dev->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);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't write to this register if the IE state is 0 as it can
|
||||
* cause deadlock.
|
||||
*/
|
||||
if (dev->iestate)
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
|
||||
}
|
||||
|
||||
static void omap_i2c_idle(struct omap_i2c_dev *dev)
|
||||
{
|
||||
u16 iv;
|
||||
|
||||
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
|
||||
if (dev->dtrev == 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_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 */
|
||||
omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
|
||||
}
|
||||
}
|
||||
|
||||
static int omap_i2c_init(struct omap_i2c_dev *dev)
|
||||
{
|
||||
u16 psc = 0, scll = 0, sclh = 0, buf = 0;
|
||||
|
@ -346,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
|
||||
SYSC_AUTOIDLE_MASK);
|
||||
|
||||
} else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
|
||||
} else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
|
||||
dev->syscstate = SYSC_AUTOIDLE_MASK;
|
||||
dev->syscstate |= SYSC_ENAWAKEUP_MASK;
|
||||
dev->syscstate |= (SYSC_IDLEMODE_SMART <<
|
||||
|
@ -468,11 +427,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|||
/* Take the I2C module out of reset: */
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
|
||||
dev->errata = 0;
|
||||
|
||||
if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
|
||||
dev->errata |= I2C_OMAP_ERRATA_I207;
|
||||
|
||||
/* Enable interrupts */
|
||||
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
|
||||
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
|
||||
|
@ -514,7 +468,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|||
struct i2c_msg *msg, int stop)
|
||||
{
|
||||
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
int r;
|
||||
unsigned long timeout;
|
||||
u16 w;
|
||||
|
||||
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
|
||||
|
@ -536,7 +490,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|||
w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
INIT_COMPLETION(dev->cmd_complete);
|
||||
dev->cmd_err = 0;
|
||||
|
||||
w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
|
||||
|
@ -584,12 +538,10 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|||
* REVISIT: We should abort the transfer on signals, but the bus goes
|
||||
* into arbitration and we're currently unable to recover from it.
|
||||
*/
|
||||
r = wait_for_completion_timeout(&dev->cmd_complete,
|
||||
OMAP_I2C_TIMEOUT);
|
||||
timeout = wait_for_completion_timeout(&dev->cmd_complete,
|
||||
OMAP_I2C_TIMEOUT);
|
||||
dev->buf_len = 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
if (timeout == 0) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
omap_i2c_init(dev);
|
||||
return -ETIMEDOUT;
|
||||
|
@ -630,7 +582,9 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|||
int i;
|
||||
int r;
|
||||
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (IS_ERR_VALUE(r))
|
||||
return r;
|
||||
|
||||
r = omap_i2c_wait_for_bb(dev);
|
||||
if (r < 0)
|
||||
|
@ -767,11 +721,11 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
|
|||
#endif
|
||||
|
||||
/*
|
||||
* OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
|
||||
* OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
|
||||
* data to DATA_REG. Otherwise some data bytes can be lost while transferring
|
||||
* them from the memory to the I2C interface.
|
||||
*/
|
||||
static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
||||
static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
||||
{
|
||||
unsigned long timeout = 10000;
|
||||
|
||||
|
@ -779,7 +733,6 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
|||
if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
|
||||
omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
|
||||
OMAP_I2C_STAT_XDR));
|
||||
*err |= OMAP_I2C_STAT_XUDF;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -792,6 +745,7 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
|
|||
return 0;
|
||||
}
|
||||
|
||||
*err |= OMAP_I2C_STAT_XUDF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -930,8 +884,8 @@ complete:
|
|||
break;
|
||||
}
|
||||
|
||||
if ((dev->errata & I2C_OMAP3_1P153) &&
|
||||
errata_omap3_1p153(dev, &stat, &err))
|
||||
if ((dev->errata & I2C_OMAP_ERRATA_I462) &&
|
||||
errata_omap3_i462(dev, &stat, &err))
|
||||
goto complete;
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
|
||||
|
@ -1048,6 +1002,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
init_completion(&dev->cmd_complete);
|
||||
|
||||
dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
|
||||
|
||||
|
@ -1057,12 +1012,19 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
dev->regs = (u8 *)reg_map_ip_v1;
|
||||
|
||||
pm_runtime_enable(dev->dev);
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (IS_ERR_VALUE(r))
|
||||
goto err_free_mem;
|
||||
|
||||
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;
|
||||
dev->errata = 0;
|
||||
|
||||
if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
|
||||
dev->errata |= I2C_OMAP_ERRATA_I207;
|
||||
|
||||
if (dev->rev <= OMAP_I2C_REV_ON_3430_3530)
|
||||
dev->errata |= I2C_OMAP_ERRATA_I462;
|
||||
|
||||
if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
|
||||
u16 s;
|
||||
|
@ -1079,7 +1041,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
dev->fifo_size = (dev->fifo_size / 2);
|
||||
|
||||
if (dev->rev >= OMAP_I2C_REV_ON_3530_4430)
|
||||
if (dev->rev >= OMAP_I2C_REV_ON_3630_4430)
|
||||
dev->b_hw = 0; /* Disable hardware fixes */
|
||||
else
|
||||
dev->b_hw = 1; /* Enable hardware fixes */
|
||||
|
@ -1095,7 +1057,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
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);
|
||||
r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
|
||||
|
||||
if (r) {
|
||||
dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
|
||||
|
@ -1105,8 +1067,6 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
|
||||
dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
|
||||
|
||||
pm_runtime_put(dev->dev);
|
||||
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
|
@ -1126,6 +1086,8 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
of_i2c_register_devices(adap);
|
||||
|
||||
pm_runtime_put(dev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
|
@ -1134,6 +1096,7 @@ err_unuse_clocks:
|
|||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
pm_runtime_put(dev->dev);
|
||||
iounmap(dev->base);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err_free_mem:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(dev);
|
||||
|
@ -1143,17 +1106,23 @@ err_release_region:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
omap_i2c_remove(struct platform_device *pdev)
|
||||
static int __devexit omap_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
free_irq(dev->irq, dev);
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
iounmap(dev->base);
|
||||
kfree(dev);
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
@ -1161,13 +1130,26 @@ omap_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#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);
|
||||
u16 iv;
|
||||
|
||||
omap_i2c_idle(_dev);
|
||||
_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
|
||||
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
|
||||
|
||||
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 */
|
||||
omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1177,23 +1159,40 @@ 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);
|
||||
if (_dev->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);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't write to this register if the IE state is 0 as it can
|
||||
* cause deadlock.
|
||||
*/
|
||||
if (_dev->iestate)
|
||||
omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
|
||||
static struct dev_pm_ops omap_i2c_pm_ops = {
|
||||
.runtime_suspend = omap_i2c_runtime_suspend,
|
||||
.runtime_resume = omap_i2c_runtime_resume,
|
||||
SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
|
||||
omap_i2c_runtime_resume, NULL)
|
||||
};
|
||||
#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
|
||||
#else
|
||||
#define OMAP_I2C_PM_OPS NULL
|
||||
#endif
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct platform_driver omap_i2c_driver = {
|
||||
.probe = omap_i2c_probe,
|
||||
.remove = omap_i2c_remove,
|
||||
.remove = __devexit_p(omap_i2c_remove),
|
||||
.driver = {
|
||||
.name = "omap_i2c",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -587,25 +587,27 @@ static struct i2c_algorithm pnx_algorithm = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int i2c_pnx_controller_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
static int i2c_pnx_controller_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
|
||||
struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(alg_data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_pnx_controller_resume(struct platform_device *pdev)
|
||||
static int i2c_pnx_controller_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
|
||||
struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
|
||||
|
||||
return clk_enable(alg_data->clk);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(i2c_pnx_pm,
|
||||
i2c_pnx_controller_suspend, i2c_pnx_controller_resume);
|
||||
#define PNX_I2C_PM (&i2c_pnx_pm)
|
||||
#else
|
||||
#define i2c_pnx_controller_suspend NULL
|
||||
#define i2c_pnx_controller_resume NULL
|
||||
#define PNX_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static int __devinit i2c_pnx_probe(struct platform_device *pdev)
|
||||
|
@ -783,11 +785,10 @@ static struct platform_driver i2c_pnx_driver = {
|
|||
.name = "pnx-i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(i2c_pnx_of_match),
|
||||
.pm = PNX_I2C_PM,
|
||||
},
|
||||
.probe = i2c_pnx_probe,
|
||||
.remove = __devexit_p(i2c_pnx_remove),
|
||||
.suspend = i2c_pnx_controller_suspend,
|
||||
.resume = i2c_pnx_controller_resume,
|
||||
};
|
||||
|
||||
static int __init i2c_adap_pnx_init(void)
|
||||
|
|
|
@ -254,7 +254,7 @@ static int __devexit puv3_i2c_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
|
||||
static int puv3_i2c_suspend(struct device *dev)
|
||||
{
|
||||
int poll_count;
|
||||
/* Disable the IIC */
|
||||
|
@ -267,23 +267,20 @@ static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int puv3_i2c_resume(struct platform_device *dev)
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
static SIMPLE_DEV_PM_OPS(puv3_i2c_pm, puv3_i2c_suspend, NULL);
|
||||
#define PUV3_I2C_PM (&puv3_i2c_pm)
|
||||
|
||||
#else
|
||||
#define puv3_i2c_suspend NULL
|
||||
#define puv3_i2c_resume NULL
|
||||
#define PUV3_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver puv3_i2c_driver = {
|
||||
.probe = puv3_i2c_probe,
|
||||
.remove = __devexit_p(puv3_i2c_remove),
|
||||
.suspend = puv3_i2c_suspend,
|
||||
.resume = puv3_i2c_resume,
|
||||
.driver = {
|
||||
.name = "PKUnity-v3-I2C",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = PUV3_I2C_PM,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ static inline unsigned int s3c24xx_get_device_quirks(struct platform_device *pde
|
|||
{
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_node(&s3c24xx_i2c_match, pdev->dev.of_node);
|
||||
match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
|
||||
return (unsigned int)match->data;
|
||||
}
|
||||
|
||||
|
@ -609,7 +609,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
|||
|
||||
if (ret != -EAGAIN) {
|
||||
clk_disable(i2c->clk);
|
||||
pm_runtime_put_sync(&adap->dev);
|
||||
pm_runtime_put(&adap->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -619,7 +619,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
|||
}
|
||||
|
||||
clk_disable(i2c->clk);
|
||||
pm_runtime_put_sync(&adap->dev);
|
||||
pm_runtime_put(&adap->dev);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* Copyright (C) 2007-2012 ST-Ericsson AB
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* ST DDC I2C master mode driver, used in e.g. U300 series platforms.
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
|
@ -139,8 +139,6 @@ module_param(scl_frequency, uint, 0644);
|
|||
* struct stu300_dev - the stu300 driver state holder
|
||||
* @pdev: parent platform device
|
||||
* @adapter: corresponding I2C adapter
|
||||
* @phybase: location of I/O area in memory
|
||||
* @physize: size of I/O area in memory
|
||||
* @clk: hardware block clock
|
||||
* @irq: assigned interrupt line
|
||||
* @cmd_issue_lock: this locks the following cmd_ variables
|
||||
|
@ -155,8 +153,6 @@ module_param(scl_frequency, uint, 0644);
|
|||
struct stu300_dev {
|
||||
struct platform_device *pdev;
|
||||
struct i2c_adapter adapter;
|
||||
resource_size_t phybase;
|
||||
resource_size_t physize;
|
||||
void __iomem *virtbase;
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
|
@ -873,64 +869,44 @@ stu300_probe(struct platform_device *pdev)
|
|||
int ret = 0;
|
||||
char clk_name[] = "I2C0";
|
||||
|
||||
dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
dev_err(&pdev->dev, "could not allocate device struct\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_no_devmem;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus_nr = pdev->id;
|
||||
clk_name[3] += (char)bus_nr;
|
||||
dev->clk = clk_get(&pdev->dev, clk_name);
|
||||
dev->clk = devm_clk_get(&pdev->dev, clk_name);
|
||||
if (IS_ERR(dev->clk)) {
|
||||
ret = PTR_ERR(dev->clk);
|
||||
dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
|
||||
goto err_no_clk;
|
||||
return PTR_ERR(dev->clk);
|
||||
}
|
||||
|
||||
dev->pdev = pdev;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto err_no_resource;
|
||||
}
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
dev->phybase = res->start;
|
||||
dev->physize = resource_size(res);
|
||||
|
||||
if (request_mem_region(dev->phybase, dev->physize,
|
||||
NAME " I/O Area") == NULL) {
|
||||
ret = -EBUSY;
|
||||
goto err_no_ioregion;
|
||||
}
|
||||
|
||||
dev->virtbase = ioremap(dev->phybase, dev->physize);
|
||||
dev->virtbase = devm_request_and_ioremap(&pdev->dev, res);
|
||||
dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
|
||||
"base %p\n", bus_nr, dev->virtbase);
|
||||
if (!dev->virtbase) {
|
||||
ret = -ENOMEM;
|
||||
goto err_no_ioremap;
|
||||
}
|
||||
if (!dev->virtbase)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
if (request_irq(dev->irq, stu300_irh, 0,
|
||||
NAME, dev)) {
|
||||
ret = -EIO;
|
||||
goto err_no_irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, dev->irq, stu300_irh, 0, NAME, dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev->speed = scl_frequency;
|
||||
|
||||
clk_enable(dev->clk);
|
||||
clk_prepare_enable(dev->clk);
|
||||
ret = stu300_init_hw(dev);
|
||||
clk_disable(dev->clk);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(&dev->pdev->dev, "error initializing hardware.\n");
|
||||
goto err_init_hw;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* IRQ event handling initialization */
|
||||
|
@ -952,57 +928,43 @@ stu300_probe(struct platform_device *pdev)
|
|||
/* i2c device drivers may be active on return from add_adapter() */
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret) {
|
||||
dev_err(&dev->pdev->dev, "failure adding ST Micro DDC "
|
||||
dev_err(&pdev->dev, "failure adding ST Micro DDC "
|
||||
"I2C adapter\n");
|
||||
goto err_add_adapter;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_add_adapter:
|
||||
err_init_hw:
|
||||
free_irq(dev->irq, dev);
|
||||
err_no_irq:
|
||||
iounmap(dev->virtbase);
|
||||
err_no_ioremap:
|
||||
release_mem_region(dev->phybase, dev->physize);
|
||||
err_no_ioregion:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
err_no_resource:
|
||||
clk_put(dev->clk);
|
||||
err_no_clk:
|
||||
kfree(dev);
|
||||
err_no_devmem:
|
||||
dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n",
|
||||
pdev->id);
|
||||
return ret;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stu300_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int stu300_suspend(struct device *device)
|
||||
{
|
||||
struct stu300_dev *dev = platform_get_drvdata(pdev);
|
||||
struct stu300_dev *dev = dev_get_drvdata(device);
|
||||
|
||||
/* Turn off everything */
|
||||
stu300_wr8(0x00, dev->virtbase + I2C_CR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stu300_resume(struct platform_device *pdev)
|
||||
static int stu300_resume(struct device *device)
|
||||
{
|
||||
int ret = 0;
|
||||
struct stu300_dev *dev = platform_get_drvdata(pdev);
|
||||
struct stu300_dev *dev = dev_get_drvdata(device);
|
||||
|
||||
clk_enable(dev->clk);
|
||||
ret = stu300_init_hw(dev);
|
||||
clk_disable(dev->clk);
|
||||
|
||||
if (ret != 0)
|
||||
dev_err(&pdev->dev, "error re-initializing hardware.\n");
|
||||
dev_err(device, "error re-initializing hardware.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume);
|
||||
#define STU300_I2C_PM (&stu300_pm)
|
||||
#else
|
||||
#define stu300_suspend NULL
|
||||
#define stu300_resume NULL
|
||||
#define STU300_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static int __exit
|
||||
|
@ -1013,12 +975,7 @@ stu300_remove(struct platform_device *pdev)
|
|||
i2c_del_adapter(&dev->adapter);
|
||||
/* Turn off everything */
|
||||
stu300_wr8(0x00, dev->virtbase + I2C_CR);
|
||||
free_irq(dev->irq, dev);
|
||||
iounmap(dev->virtbase);
|
||||
release_mem_region(dev->phybase, dev->physize);
|
||||
clk_put(dev->clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1026,10 +983,9 @@ static struct platform_driver stu300_i2c_driver = {
|
|||
.driver = {
|
||||
.name = NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = STU300_I2C_PM,
|
||||
},
|
||||
.remove = __exit_p(stu300_remove),
|
||||
.suspend = stu300_suspend,
|
||||
.resume = stu300_resume,
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -97,8 +97,21 @@
|
|||
#define I2C_HEADER_10BIT_ADDR (1<<18)
|
||||
#define I2C_HEADER_IE_ENABLE (1<<17)
|
||||
#define I2C_HEADER_REPEAT_START (1<<16)
|
||||
#define I2C_HEADER_CONTINUE_XFER (1<<15)
|
||||
#define I2C_HEADER_MASTER_ADDR_SHIFT 12
|
||||
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
|
||||
/*
|
||||
* msg_end_type: The bus control which need to be send at end of transfer.
|
||||
* @MSG_END_STOP: Send stop pulse at end of transfer.
|
||||
* @MSG_END_REPEAT_START: Send repeat start at end of transfer.
|
||||
* @MSG_END_CONTINUE: The following on message is coming and so do not send
|
||||
* stop or repeat start.
|
||||
*/
|
||||
enum msg_end_type {
|
||||
MSG_END_STOP,
|
||||
MSG_END_REPEAT_START,
|
||||
MSG_END_CONTINUE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_i2c_dev - per device i2c context
|
||||
|
@ -106,7 +119,6 @@
|
|||
* @adapter: core i2c layer adapter information
|
||||
* @clk: clock reference for i2c controller
|
||||
* @i2c_clk: clock reference for i2c bus
|
||||
* @iomem: memory resource for registers
|
||||
* @base: ioremapped registers cookie
|
||||
* @cont_id: i2c controller id, used for for packet header
|
||||
* @irq: irq number of transfer complete interrupt
|
||||
|
@ -124,7 +136,6 @@ struct tegra_i2c_dev {
|
|||
struct i2c_adapter adapter;
|
||||
struct clk *clk;
|
||||
struct clk *i2c_clk;
|
||||
struct resource *iomem;
|
||||
void __iomem *base;
|
||||
int cont_id;
|
||||
int irq;
|
||||
|
@ -165,6 +176,10 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
|||
unsigned long reg)
|
||||
{
|
||||
writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
|
||||
/* Read back register to make sure that register writes completed */
|
||||
if (reg != I2C_TX_FIFO)
|
||||
readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
}
|
||||
|
||||
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
|
||||
|
@ -449,7 +464,7 @@ err:
|
|||
}
|
||||
|
||||
static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
struct i2c_msg *msg, int stop)
|
||||
struct i2c_msg *msg, enum msg_end_type end_state)
|
||||
{
|
||||
u32 packet_header;
|
||||
u32 int_mask;
|
||||
|
@ -476,7 +491,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
|
||||
|
||||
packet_header = I2C_HEADER_IE_ENABLE;
|
||||
if (!stop)
|
||||
if (end_state == MSG_END_CONTINUE)
|
||||
packet_header |= I2C_HEADER_CONTINUE_XFER;
|
||||
else if (end_state == MSG_END_REPEAT_START)
|
||||
packet_header |= I2C_HEADER_REPEAT_START;
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
packet_header |= msg->addr;
|
||||
|
@ -548,8 +565,14 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
|
||||
clk_prepare_enable(i2c_dev->clk);
|
||||
for (i = 0; i < num; i++) {
|
||||
int stop = (i == (num - 1)) ? 1 : 0;
|
||||
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
|
||||
enum msg_end_type end_type = MSG_END_STOP;
|
||||
if (i < (num - 1)) {
|
||||
if (msgs[i + 1].flags & I2C_M_NOSTART)
|
||||
end_type = MSG_END_CONTINUE;
|
||||
else
|
||||
end_type = MSG_END_REPEAT_START;
|
||||
}
|
||||
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
@ -559,7 +582,8 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
|
||||
static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
|
||||
I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm tegra_i2c_algo = {
|
||||
|
@ -572,7 +596,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
|||
struct tegra_i2c_dev *i2c_dev;
|
||||
struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
struct resource *iomem;
|
||||
struct clk *clk;
|
||||
struct clk *i2c_clk;
|
||||
const unsigned int *prop;
|
||||
|
@ -585,50 +608,41 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "no mem resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
iomem = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (!iomem) {
|
||||
dev_err(&pdev->dev, "I2C region already claimed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
base = ioremap(iomem->start, resource_size(iomem));
|
||||
base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!base) {
|
||||
dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
|
||||
return -ENOMEM;
|
||||
dev_err(&pdev->dev, "Cannot request/ioremap I2C registers\n");
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no irq resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err_iounmap;
|
||||
return -EINVAL;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
clk = clk_get(&pdev->dev, NULL);
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "missing controller clock");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_release_region;
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
i2c_clk = clk_get(&pdev->dev, "i2c");
|
||||
i2c_clk = devm_clk_get(&pdev->dev, "i2c");
|
||||
if (IS_ERR(i2c_clk)) {
|
||||
dev_err(&pdev->dev, "missing bus clock");
|
||||
ret = PTR_ERR(i2c_clk);
|
||||
goto err_clk_put;
|
||||
return PTR_ERR(i2c_clk);
|
||||
}
|
||||
|
||||
i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL);
|
||||
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
|
||||
if (!i2c_dev) {
|
||||
ret = -ENOMEM;
|
||||
goto err_i2c_clk_put;
|
||||
dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_dev->base = base;
|
||||
i2c_dev->clk = clk;
|
||||
i2c_dev->i2c_clk = i2c_clk;
|
||||
i2c_dev->iomem = iomem;
|
||||
i2c_dev->adapter.algo = &tegra_i2c_algo;
|
||||
i2c_dev->irq = irq;
|
||||
i2c_dev->cont_id = pdev->id;
|
||||
|
@ -657,13 +671,14 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
|||
ret = tegra_i2c_init(i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to initialize i2c controller");
|
||||
goto err_free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
|
||||
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
|
||||
tegra_i2c_isr, 0, pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
|
||||
goto err_free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_prepare_enable(i2c_dev->i2c_clk);
|
||||
|
@ -681,45 +696,26 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
|
|||
ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add I2C adapter\n");
|
||||
goto err_free_irq;
|
||||
clk_disable_unprepare(i2c_dev->i2c_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
of_i2c_register_devices(&i2c_dev->adapter);
|
||||
|
||||
return 0;
|
||||
err_free_irq:
|
||||
free_irq(i2c_dev->irq, i2c_dev);
|
||||
err_free:
|
||||
kfree(i2c_dev);
|
||||
err_i2c_clk_put:
|
||||
clk_put(i2c_clk);
|
||||
err_clk_put:
|
||||
clk_put(clk);
|
||||
err_release_region:
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
err_iounmap:
|
||||
iounmap(base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tegra_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
i2c_del_adapter(&i2c_dev->adapter);
|
||||
free_irq(i2c_dev->irq, i2c_dev);
|
||||
clk_put(i2c_dev->i2c_clk);
|
||||
clk_put(i2c_dev->clk);
|
||||
release_mem_region(i2c_dev->iomem->start,
|
||||
resource_size(i2c_dev->iomem));
|
||||
iounmap(i2c_dev->base);
|
||||
kfree(i2c_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int tegra_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
i2c_lock_adapter(&i2c_dev->adapter);
|
||||
i2c_dev->is_suspended = true;
|
||||
|
@ -728,9 +724,9 @@ static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_resume(struct platform_device *pdev)
|
||||
static int tegra_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
i2c_lock_adapter(&i2c_dev->adapter);
|
||||
|
@ -748,6 +744,11 @@ static int tegra_i2c_resume(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume);
|
||||
#define TEGRA_I2C_PM (&tegra_i2c_pm)
|
||||
#else
|
||||
#define TEGRA_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
|
@ -758,21 +759,16 @@ static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
|
|||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
|
||||
#else
|
||||
#define tegra_i2c_of_match NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_i2c_driver = {
|
||||
.probe = tegra_i2c_probe,
|
||||
.remove = __devexit_p(tegra_i2c_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = tegra_i2c_suspend,
|
||||
.resume = tegra_i2c_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = "tegra-i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tegra_i2c_of_match,
|
||||
.of_match_table = of_match_ptr(tegra_i2c_of_match),
|
||||
.pm = TEGRA_I2C_PM,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ timberdale_xiic_platform_data = {
|
|||
|
||||
static __devinitdata struct ocores_i2c_platform_data
|
||||
timberdale_ocores_platform_data = {
|
||||
.regstep = 4,
|
||||
.reg_shift = 2,
|
||||
.clock_khz = 62500,
|
||||
.devices = timberdale_i2c_board_info,
|
||||
.num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
#define _LINUX_I2C_OCORES_H
|
||||
|
||||
struct ocores_i2c_platform_data {
|
||||
u32 regstep; /* distance between registers */
|
||||
u32 reg_shift; /* register offset shift value */
|
||||
u32 reg_io_width; /* register io read/write width */
|
||||
u32 clock_khz; /* input clock in kHz */
|
||||
u8 num_devices; /* number of devices in the devices list */
|
||||
struct i2c_board_info const *devices; /* devices connected to the bus */
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef __PLAT_I2C_H
|
||||
#define __PLAT_I2C_H
|
||||
#ifndef __PDATA_I2C_NOMADIK_H
|
||||
#define __PDATA_I2C_NOMADIK_H
|
||||
|
||||
enum i2c_freq_mode {
|
||||
I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */
|
||||
|
@ -36,4 +36,4 @@ struct nmk_i2c_controller {
|
|||
enum i2c_freq_mode sm;
|
||||
};
|
||||
|
||||
#endif /* __PLAT_I2C_H */
|
||||
#endif /* __PDATA_I2C_NOMADIK_H */
|
Loading…
Reference in New Issue