mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
fix conflict for commit spi & touch screen driver
This commit is contained in:
@@ -334,6 +334,90 @@ static struct platform_device android_pmem_vpu_device = {
|
||||
.platform_data = &android_pmem_vpu_pdata,
|
||||
},
|
||||
};
|
||||
/*****************************************************************************************
|
||||
* i2c devices
|
||||
* author: kfx@rock-chips.com
|
||||
*****************************************************************************************/
|
||||
static int rk29_i2c0_io_init(void)
|
||||
{
|
||||
rk29_mux_api_set(GPIO2B7_I2C0SCL_NAME, GPIO2L_I2C0_SCL);
|
||||
rk29_mux_api_set(GPIO2B6_I2C0SDA_NAME, GPIO2L_I2C0_SDA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk29_i2c1_io_init(void)
|
||||
{
|
||||
rk29_mux_api_set(GPIO1A7_I2C1SCL_NAME, GPIO1L_I2C1_SCL);
|
||||
rk29_mux_api_set(GPIO1A6_I2C1SDA_NAME, GPIO1L_I2C1_SDA);
|
||||
return 0;
|
||||
}
|
||||
static int rk29_i2c2_io_init(void)
|
||||
{
|
||||
rk29_mux_api_set(GPIO5D4_I2C2SCL_NAME, GPIO5H_I2C2_SCL);
|
||||
rk29_mux_api_set(GPIO5D3_I2C2SDA_NAME, GPIO5H_I2C2_SDA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk29_i2c3_io_init(void)
|
||||
{
|
||||
rk29_mux_api_set(GPIO2B5_UART3RTSN_I2C3SCL_NAME, GPIO2L_I2C3_SCL);
|
||||
rk29_mux_api_set(GPIO2B4_UART3CTSN_I2C3SDA_NAME, GPIO2L_I2C3_SDA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rk29_i2c_platform_data default_i2c0_data = {
|
||||
.bus_num = 0,
|
||||
.flags = 0,
|
||||
.slave_addr = 0xff,
|
||||
.scl_rate = 400*1000,
|
||||
.mode = I2C_MODE_IRQ,
|
||||
.io_init = rk29_i2c0_io_init,
|
||||
};
|
||||
struct rk29_i2c_platform_data default_i2c1_data = {
|
||||
.bus_num = 1,
|
||||
.flags = 0,
|
||||
.slave_addr = 0xff,
|
||||
.scl_rate = 400*1000,
|
||||
.mode = I2C_MODE_POLL,
|
||||
.io_init = rk29_i2c1_io_init,
|
||||
};
|
||||
struct rk29_i2c_platform_data default_i2c2_data = {
|
||||
.bus_num = 2,
|
||||
.flags = 0,
|
||||
.slave_addr = 0xff,
|
||||
.scl_rate = 400*1000,
|
||||
.mode = I2C_MODE_IRQ,
|
||||
.io_init = rk29_i2c2_io_init,
|
||||
};
|
||||
struct rk29_i2c_platform_data default_i2c3_data = {
|
||||
.bus_num = 3,
|
||||
.flags = 0,
|
||||
.slave_addr = 0xff,
|
||||
.scl_rate = 400*1000,
|
||||
.mode = I2C_MODE_POLL,
|
||||
.io_init = rk29_i2c3_io_init,
|
||||
};
|
||||
|
||||
|
||||
static struct i2c_board_info __initdata board_i2c0_devices[] = {
|
||||
#if defined (CONFIG_RK1000_CONTROL)
|
||||
{
|
||||
.type = "rk1000_control",
|
||||
.addr = 0x40,
|
||||
.flags = 0,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
static struct i2c_board_info __initdata board_i2c1_devices[] = {
|
||||
|
||||
};
|
||||
static struct i2c_board_info __initdata board_i2c2_devices[] = {
|
||||
|
||||
};
|
||||
static struct i2c_board_info __initdata board_i2c3_devices[] = {
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
* SDMMC devices
|
||||
@@ -347,7 +431,7 @@ void rk29_sdmmc0_cfg_gpio(struct platform_device *dev)
|
||||
rk29_mux_api_set(GPIO1D3_SDMMC0DATA1_NAME, GPIO1H_SDMMC0_DATA1);
|
||||
rk29_mux_api_set(GPIO1D4_SDMMC0DATA2_NAME, GPIO1H_SDMMC0_DATA2);
|
||||
rk29_mux_api_set(GPIO1D5_SDMMC0DATA3_NAME, GPIO1H_SDMMC0_DATA3);
|
||||
rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N);
|
||||
rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N);
|
||||
}
|
||||
|
||||
#define CONFIG_SDMMC0_USE_DMA
|
||||
@@ -375,7 +459,7 @@ void rk29_sdmmc1_cfg_gpio(struct platform_device *dev)
|
||||
rk29_mux_api_set(GPIO1C3_SDMMC1DATA0_NAME, GPIO1H_SDMMC1_DATA0);
|
||||
rk29_mux_api_set(GPIO1C4_SDMMC1DATA1_NAME, GPIO1H_SDMMC1_DATA1);
|
||||
rk29_mux_api_set(GPIO1C5_SDMMC1DATA2_NAME, GPIO1H_SDMMC1_DATA2);
|
||||
rk29_mux_api_set(GPIO1C6_SDMMC1DATA3_NAME, GPIO1H_SDMMC1_DATA3);
|
||||
rk29_mux_api_set(GPIO1C6_SDMMC1DATA3_NAME, GPIO1H_SDMMC1_DATA3);
|
||||
}
|
||||
|
||||
struct rk29_sdmmc_platform_data default_sdmmc1_data = {
|
||||
@@ -464,6 +548,20 @@ static struct platform_device *devices[] __initdata = {
|
||||
&rk29xx_device_spi0m,
|
||||
&rk29xx_device_spi1m,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_I2C0_RK29
|
||||
&rk29_device_i2c0,
|
||||
#endif
|
||||
#ifdef CONFIG_I2C1_RK29
|
||||
&rk29_device_i2c1,
|
||||
#endif
|
||||
#ifdef CONFIG_I2C2_RK29
|
||||
&rk29_device_i2c2,
|
||||
#endif
|
||||
#ifdef CONFIG_I2C3_RK29
|
||||
&rk29_device_i2c3,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SDMMC0_RK29
|
||||
&rk29_device_sdmmc0,
|
||||
#endif
|
||||
@@ -686,7 +784,24 @@ static void __init machine_rk29_init_irq(void)
|
||||
static void __init machine_rk29_board_init(void)
|
||||
{
|
||||
rk29_board_iomux_init();
|
||||
platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
#ifdef CONFIG_I2C0_RK29
|
||||
i2c_register_board_info(default_i2c0_data.bus_num, board_i2c0_devices,
|
||||
ARRAY_SIZE(board_i2c0_devices));
|
||||
#endif
|
||||
#ifdef CONFIG_I2C1_RK29
|
||||
i2c_register_board_info(default_i2c1_data.bus_num, board_i2c1_devices,
|
||||
ARRAY_SIZE(board_i2c1_devices));
|
||||
#endif
|
||||
#ifdef CONFIG_I2C2_RK29
|
||||
i2c_register_board_info(default_i2c2_data.bus_num, board_i2c2_devices,
|
||||
ARRAY_SIZE(board_i2c2_devices));
|
||||
#endif
|
||||
#ifdef CONFIG_I2C3_RK29
|
||||
i2c_register_board_info(default_i2c3_data.bus_num, board_i2c3_devices,
|
||||
ARRAY_SIZE(board_i2c3_devices));
|
||||
#endif
|
||||
|
||||
spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices));
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,93 @@
|
||||
#include <mach/rk29_iomap.h>
|
||||
#include <mach/rk29-dma-pl330.h>
|
||||
#include "devices.h"
|
||||
#ifdef CONFIG_I2C_RK29
|
||||
static struct resource resources_i2c0[] = {
|
||||
{
|
||||
.start = IRQ_I2C0,
|
||||
.end = IRQ_I2C0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = RK29_I2C0_PHYS,
|
||||
.end = RK29_I2C0_PHYS + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
static struct resource resources_i2c1[] = {
|
||||
{
|
||||
.start = IRQ_I2C1,
|
||||
.end = IRQ_I2C1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = RK29_I2C1_PHYS,
|
||||
.end = RK29_I2C1_PHYS + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
static struct resource resources_i2c2[] = {
|
||||
{
|
||||
.start = IRQ_I2C2,
|
||||
.end = IRQ_I2C2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = RK29_I2C2_PHYS,
|
||||
.end = RK29_I2C2_PHYS + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
static struct resource resources_i2c3[] = {
|
||||
{
|
||||
.start = IRQ_I2C3,
|
||||
.end = IRQ_I2C3,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = RK29_I2C3_PHYS,
|
||||
.end = RK29_I2C3_PHYS + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device rk29_device_i2c0 = {
|
||||
.name = "rk29_i2c",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(resources_i2c0),
|
||||
.resource = resources_i2c0,
|
||||
.dev = {
|
||||
.platform_data = &default_i2c0_data,
|
||||
},
|
||||
};
|
||||
struct platform_device rk29_device_i2c1 = {
|
||||
.name = "rk29_i2c",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(resources_i2c1),
|
||||
.resource = resources_i2c1,
|
||||
.dev = {
|
||||
.platform_data = &default_i2c1_data,
|
||||
},
|
||||
};
|
||||
struct platform_device rk29_device_i2c2 = {
|
||||
.name = "rk29_i2c",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(resources_i2c2),
|
||||
.resource = resources_i2c2,
|
||||
.dev = {
|
||||
.platform_data = &default_i2c2_data,
|
||||
},
|
||||
};
|
||||
struct platform_device rk29_device_i2c3 = {
|
||||
.name = "rk29_i2c",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(resources_i2c3),
|
||||
.resource = resources_i2c3,
|
||||
.dev = {
|
||||
.platform_data = &default_i2c3_data,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_SDMMC0_RK29
|
||||
|
||||
@@ -17,7 +17,14 @@
|
||||
#define __ARCH_ARM_MACH_RK29_DEVICES_H
|
||||
|
||||
extern struct rk29_nand_platform_data rk29_nand_data;
|
||||
|
||||
extern struct rk29_i2c_platform_data default_i2c0_data;
|
||||
extern struct rk29_i2c_platform_data default_i2c1_data;
|
||||
extern struct rk29_i2c_platform_data default_i2c2_data;
|
||||
extern struct rk29_i2c_platform_data default_i2c3_data;
|
||||
extern struct platform_device rk29_device_i2c0;
|
||||
extern struct platform_device rk29_device_i2c1;
|
||||
extern struct platform_device rk29_device_i2c2;
|
||||
extern struct platform_device rk29_device_i2c3;
|
||||
extern struct platform_device rk29_device_uart0;
|
||||
extern struct platform_device rk29_device_uart1;
|
||||
extern struct platform_device rk29_device_uart2;
|
||||
|
||||
@@ -77,6 +77,17 @@ struct rk29_sdmmc_platform_data {
|
||||
int (*status)(struct device *);
|
||||
int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
|
||||
};
|
||||
struct rk29_i2c_platform_data {
|
||||
int bus_num;
|
||||
unsigned int flags;
|
||||
unsigned int slave_addr;
|
||||
unsigned long scl_rate;
|
||||
#define I2C_MODE_IRQ 0
|
||||
#define I2C_MODE_POLL 1
|
||||
unsigned int mode:1;
|
||||
int (*io_init)(void);
|
||||
int (*io_deinit)(void);
|
||||
};
|
||||
|
||||
void __init rk29_map_common_io(void);
|
||||
void __init rk29_clock_init(void);
|
||||
|
||||
@@ -7,23 +7,63 @@ menu "I2C Hardware Bus support"
|
||||
config I2C_RK2818
|
||||
tristate "RK2818 i2c interface (I2C)"
|
||||
depends on ARCH_RK2818
|
||||
default y
|
||||
help
|
||||
This supports the use of the I2C interface on rk2818 processors.
|
||||
|
||||
if I2C_RK2818
|
||||
comment "Now, there are two I2C interfaces selected by developer, I2C0 and I2C1."
|
||||
comment "Now, there are two I2C interfaces selected by developer."
|
||||
|
||||
menuconfig I2C0_RK2818
|
||||
tristate "RK2818 I2C0 interface support"
|
||||
config I2C0_RK2818
|
||||
bool "RK2818 I2C0 interface support"
|
||||
default y
|
||||
depends on ARCH_RK2818
|
||||
help
|
||||
This supports the use of the I2C0 interface on rk2818 processors.
|
||||
menuconfig I2C1_RK2818
|
||||
tristate "RK2818 I2C1 interface support"
|
||||
config I2C1_RK2818
|
||||
bool "RK2818 I2C1 interface support"
|
||||
default y
|
||||
depends on ARCH_RK2818
|
||||
help
|
||||
This supports the use of the I2C1 interface on rk2818 processors.
|
||||
endif
|
||||
config I2C_RK29
|
||||
tristate "RK29 i2c interface (I2C)"
|
||||
depends on ARCH_RK29
|
||||
default y
|
||||
help
|
||||
This supports the use of the I2C interface(i2c0 ~ i2c3) on rk29 processors.
|
||||
|
||||
if I2C_RK29
|
||||
comment "Now, there are four I2C interfaces selected by developer."
|
||||
|
||||
config I2C0_RK29
|
||||
bool "RK29 I2C0 interface support"
|
||||
default y
|
||||
depends on ARCH_RK29
|
||||
help
|
||||
This supports the use of the I2C0 interface on rk29 processors.
|
||||
|
||||
config I2C1_RK29
|
||||
bool "RK29 I2C1 interface support"
|
||||
default y
|
||||
depends on ARCH_RK29
|
||||
help
|
||||
This supports the use of the I2C1 interface on rk29 processors.
|
||||
|
||||
config I2C2_RK29
|
||||
bool "RK29 I2C2 interface support"
|
||||
default y
|
||||
depends on ARCH_RK29
|
||||
help
|
||||
This supports the use of the I2C2 interface on rk29 processors.
|
||||
|
||||
config I2C3_RK29
|
||||
bool "RK29 I2C3 interface support"
|
||||
default y
|
||||
depends on ARCH_RK29 && !UART3_CTS_RTS_RK29
|
||||
help
|
||||
This supports the use of the I2C3 interface on rk29 processors.
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Makefile for the i2c bus drivers.
|
||||
#
|
||||
obj-$(CONFIG_I2C_RK2818) += i2c-rk2818.o
|
||||
obj-$(CONFIG_I2C_RK29) += i2c-rk29.o
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* drivers/i2c/busses/i2c_rk2818.c
|
||||
/* drivers/i2c/busses/i2c_rockchip.c
|
||||
*
|
||||
* Copyright (C) 2010 ROCKCHIP, Inc.
|
||||
*
|
||||
@@ -29,8 +29,8 @@
|
||||
#include <mach/board.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "i2c-rk2818.h"
|
||||
#define DRV_NAME "rk2818_i2c"
|
||||
#include "i2c-rockchip.h"
|
||||
#define DRV_NAME "rockchip_i2c"
|
||||
|
||||
#define RK2818_I2C_TIMEOUT (msecs_to_jiffies(500))
|
||||
#define RK2818_DELAY_TIME 2
|
||||
@@ -42,13 +42,13 @@
|
||||
#define i2c_dbg(dev, format, arg...)
|
||||
#endif
|
||||
|
||||
enum rk2818_error {
|
||||
enum rockchip_error {
|
||||
RK2818_ERROR_NONE = 0,
|
||||
RK2818_ERROR_ARBITR_LOSE,
|
||||
RK2818_ERROR_UNKNOWN
|
||||
};
|
||||
|
||||
enum rk2818_event {
|
||||
enum rockchip_event {
|
||||
RK2818_EVENT_NONE = 0,
|
||||
/* master has received ack(MTX mode)
|
||||
means that data has been sent to slave.
|
||||
@@ -61,7 +61,7 @@ enum rk2818_event {
|
||||
RK2818_EVENT_MAX
|
||||
};
|
||||
|
||||
struct rk2818_i2c_data {
|
||||
struct rockchip_i2c_data {
|
||||
struct device *dev;
|
||||
struct i2c_adapter adap;
|
||||
void __iomem *regs;
|
||||
@@ -78,8 +78,8 @@ struct rk2818_i2c_data {
|
||||
|
||||
spinlock_t cmd_lock;
|
||||
struct completion cmd_complete;
|
||||
enum rk2818_event cmd_event;
|
||||
enum rk2818_error cmd_err;
|
||||
enum rockchip_event cmd_event;
|
||||
enum rockchip_error cmd_err;
|
||||
|
||||
unsigned int msg_idx;
|
||||
unsigned int msg_num;
|
||||
@@ -88,16 +88,16 @@ struct rk2818_i2c_data {
|
||||
#endif
|
||||
};
|
||||
|
||||
static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c);
|
||||
static void rockchip_i2c_init_hw(struct rockchip_i2c_data *i2c);
|
||||
|
||||
static inline void rk2818_i2c_disable_irqs(struct rk2818_i2c_data *i2c)
|
||||
static inline void rockchip_i2c_disable_irqs(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
tmp = readl(i2c->regs + I2C_IER);
|
||||
writel(tmp & IRQ_ALL_DISABLE, i2c->regs + I2C_IER);
|
||||
}
|
||||
static inline void rk2818_i2c_enable_irqs(struct rk2818_i2c_data *i2c)
|
||||
static inline void rockchip_i2c_enable_irqs(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
@@ -106,7 +106,7 @@ static inline void rk2818_i2c_enable_irqs(struct rk2818_i2c_data *i2c)
|
||||
}
|
||||
|
||||
/* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
|
||||
static void rk2818_i2c_calcdivisor(unsigned long pclk,
|
||||
static void rockchip_i2c_calcdivisor(unsigned long pclk,
|
||||
unsigned long scl_rate,
|
||||
unsigned long *real_rate,
|
||||
unsigned int *rem, unsigned int *exp)
|
||||
@@ -131,9 +131,13 @@ static void rk2818_i2c_calcdivisor(unsigned long pclk,
|
||||
return;
|
||||
}
|
||||
/* set i2c bus scl rate */
|
||||
static void rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
|
||||
static void rockchip_i2c_clockrate(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_RK2818
|
||||
struct rk2818_i2c_platform_data *pdata = i2c->dev->platform_data;
|
||||
#else
|
||||
struct rk29_i2c_platform_data *pdata = i2c->dev->platform_data;
|
||||
#endif
|
||||
unsigned int rem = 0, exp = 0;
|
||||
unsigned long scl_rate, real_rate = 0, tmp;
|
||||
|
||||
@@ -141,7 +145,7 @@ static void rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
|
||||
|
||||
scl_rate = (i2c->scl_rate) ? i2c->scl_rate : ((pdata->scl_rate)? pdata->scl_rate:100000);
|
||||
|
||||
rk2818_i2c_calcdivisor(i2c->i2c_rate, scl_rate, &real_rate, &rem, &exp);
|
||||
rockchip_i2c_calcdivisor(i2c->i2c_rate, scl_rate, &real_rate, &rem, &exp);
|
||||
|
||||
tmp = readl(i2c->regs + I2C_OPR);
|
||||
tmp |= exp;
|
||||
@@ -155,7 +159,7 @@ static void rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
|
||||
i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
|
||||
return;
|
||||
}
|
||||
static int rk2818_event_occurred(struct rk2818_i2c_data *i2c)
|
||||
static int rockchip_event_occurred(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
unsigned long isr;
|
||||
|
||||
@@ -195,28 +199,28 @@ static int rk2818_event_occurred(struct rk2818_i2c_data *i2c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t rk2818_i2c_irq(int irq, void *data)
|
||||
static irqreturn_t rockchip_i2c_irq(int irq, void *data)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)data;
|
||||
struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)data;
|
||||
int res;
|
||||
|
||||
rk2818_i2c_disable_irqs(i2c);
|
||||
rockchip_i2c_disable_irqs(i2c);
|
||||
spin_lock(&i2c->cmd_lock);
|
||||
res = rk2818_event_occurred(i2c);
|
||||
res = rockchip_event_occurred(i2c);
|
||||
if(res)
|
||||
//if(res || i2c->cmd_err != RK2818_ERROR_NONE)
|
||||
complete(&i2c->cmd_complete);
|
||||
spin_unlock(&i2c->cmd_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
static int wait_for_completion_poll_timeout(struct rk2818_i2c_data *i2c, unsigned long timeout)
|
||||
static int wait_for_completion_poll_timeout(struct rockchip_i2c_data *i2c, unsigned long timeout)
|
||||
{
|
||||
unsigned int time = RK2818_DELAY_TIME;
|
||||
int res;
|
||||
|
||||
while(!time_after(jiffies, jiffies + timeout))
|
||||
{
|
||||
res = rk2818_event_occurred(i2c);
|
||||
res = rockchip_event_occurred(i2c);
|
||||
if(res)
|
||||
//if(res || (i2c->cmd_err != RK2818_ERROR_NONE && i2c->cmd_err != RK2818_ERROR_UNKNOWN))
|
||||
return 1;
|
||||
@@ -226,8 +230,8 @@ static int wait_for_completion_poll_timeout(struct rk2818_i2c_data *i2c, unsigne
|
||||
return 0;
|
||||
|
||||
}
|
||||
static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
|
||||
enum rk2818_event mr_event)
|
||||
static int rockchip_wait_event(struct rockchip_i2c_data *i2c,
|
||||
enum rockchip_event mr_event)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
@@ -247,7 +251,7 @@ static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
|
||||
|
||||
spin_unlock_irqrestore(&i2c->cmd_lock,flags);
|
||||
|
||||
rk2818_i2c_enable_irqs(i2c);
|
||||
rockchip_i2c_enable_irqs(i2c);
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
|
||||
RK2818_I2C_TIMEOUT);
|
||||
@@ -266,7 +270,7 @@ static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk2818_wait_while_busy(struct rk2818_i2c_data *i2c)
|
||||
static int rockchip_wait_while_busy(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
|
||||
unsigned long lsr;
|
||||
@@ -282,7 +286,7 @@ static int rk2818_wait_while_busy(struct rk2818_i2c_data *i2c)
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
static int rk2818_i2c_stop(struct rk2818_i2c_data *i2c)
|
||||
static int rockchip_i2c_stop(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
|
||||
unsigned int time = RK2818_DELAY_TIME;
|
||||
@@ -301,7 +305,7 @@ static int rk2818_i2c_stop(struct rk2818_i2c_data *i2c)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
}
|
||||
static int rk2818_send_2nd_addr(struct rk2818_i2c_data *i2c,
|
||||
static int rockchip_send_2nd_addr(struct rockchip_i2c_data *i2c,
|
||||
struct i2c_msg *msg, int start)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -315,14 +319,14 @@ static int rk2818_send_2nd_addr(struct rk2818_i2c_data *i2c,
|
||||
i2c_dbg(i2c->dev, "i2c send addr_2nd: %lx\n", addr_2nd);
|
||||
writel(addr_2nd, i2c->regs + I2C_MTXR);
|
||||
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "after sent addr_2nd, i2c wait for ACK timeout\n");
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rk2818_send_address(struct rk2818_i2c_data *i2c,
|
||||
static int rockchip_send_address(struct rockchip_i2c_data *i2c,
|
||||
struct i2c_msg *msg, int start)
|
||||
{
|
||||
unsigned long addr_1st;
|
||||
@@ -348,7 +352,7 @@ static int rk2818_send_address(struct rk2818_i2c_data *i2c,
|
||||
|
||||
if (start)
|
||||
{
|
||||
if((ret = rk2818_wait_while_busy(i2c)) != 0)
|
||||
if((ret = rockchip_wait_while_busy(i2c)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "i2c is busy, when send address\n");
|
||||
return ret;
|
||||
@@ -358,17 +362,17 @@ static int rk2818_send_address(struct rk2818_i2c_data *i2c,
|
||||
else
|
||||
writel(I2C_LCMR_START|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
|
||||
if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "after sent addr_1st, i2c wait for ACK timeout\n");
|
||||
return ret;
|
||||
}
|
||||
if(start && (msg->flags & I2C_M_TEN))
|
||||
ret = rk2818_send_2nd_addr(i2c, msg, start);
|
||||
ret = rockchip_send_2nd_addr(i2c, msg, start);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk2818_i2c_send_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
|
||||
static int rockchip_i2c_send_msg(struct rockchip_i2c_data *i2c, struct i2c_msg *msg)
|
||||
{
|
||||
int i, ret = 0;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
@@ -387,12 +391,12 @@ static int rk2818_i2c_send_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
|
||||
*/
|
||||
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
|
||||
if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rk2818_i2c_recv_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
|
||||
static int rockchip_i2c_recv_msg(struct rockchip_i2c_data *i2c, struct i2c_msg *msg)
|
||||
{
|
||||
int i, ret = 0;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
@@ -404,7 +408,7 @@ static int rk2818_i2c_recv_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
|
||||
for(i = 0; i < msg->len; i++)
|
||||
{
|
||||
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
if((ret = rk2818_wait_event(i2c, RK2818_EVENT_MRX_NEED_ACK)) != 0)
|
||||
if((ret = rockchip_wait_event(i2c, RK2818_EVENT_MRX_NEED_ACK)) != 0)
|
||||
return ret;
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr &= I2C_CONR_ACK;
|
||||
@@ -414,10 +418,10 @@ static int rk2818_i2c_recv_msg(struct rk2818_i2c_data *i2c, struct i2c_msg *msg)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rk2818_xfer_msg(struct i2c_adapter *adap,
|
||||
static int rockchip_xfer_msg(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, int start, int stop)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
|
||||
struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)adap->algo_data;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
int ret = 0;
|
||||
|
||||
@@ -432,24 +436,24 @@ static int rk2818_xfer_msg(struct i2c_adapter *adap,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if((ret = rk2818_send_address(i2c, msg, start))!= 0)
|
||||
if((ret = rockchip_send_address(i2c, msg, start))!= 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk2818_send_address timeout\n");
|
||||
dev_err(i2c->dev, "<error>rockchip_send_address timeout\n");
|
||||
goto exit;
|
||||
}
|
||||
if(msg->flags & I2C_M_RD)
|
||||
{
|
||||
if((ret = rk2818_i2c_recv_msg(i2c, msg)) != 0)
|
||||
if((ret = rockchip_i2c_recv_msg(i2c, msg)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk2818_i2c_recv_msg timeout\n");
|
||||
dev_err(i2c->dev, "<error>rockchip_i2c_recv_msg timeout\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((ret = rk2818_i2c_send_msg(i2c, msg)) != 0)
|
||||
if((ret = rockchip_i2c_send_msg(i2c, msg)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk2818_i2c_send_msg timeout\n");
|
||||
dev_err(i2c->dev, "<error>rockchip_i2c_send_msg timeout\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@@ -460,9 +464,9 @@ exit:
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr |= I2C_CONR_NAK;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
if((ret = rk2818_i2c_stop(i2c)) != 0)
|
||||
if((ret = rockchip_i2c_stop(i2c)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk2818_i2c_stop timeout\n");
|
||||
dev_err(i2c->dev, "<error>rockchip_i2c_stop timeout\n");
|
||||
}
|
||||
|
||||
//not I2C code,add by sxj,used for extend gpio intrrupt,set SCL and SDA pin.
|
||||
@@ -480,12 +484,12 @@ exit:
|
||||
|
||||
}
|
||||
|
||||
static int rk2818_i2c_xfer(struct i2c_adapter *adap,
|
||||
static int rockchip_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
int ret = -1;
|
||||
int i;
|
||||
struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
|
||||
struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)adap->algo_data;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
/*
|
||||
if(i2c->suspended ==1)
|
||||
@@ -499,7 +503,7 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap,
|
||||
conr |= I2C_CONR_MPORT_ENABLE;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
|
||||
rk2818_i2c_init_hw(i2c);
|
||||
rockchip_i2c_init_hw(i2c);
|
||||
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr &= I2C_CONR_ACK;
|
||||
@@ -507,11 +511,11 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap,
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
ret = rk2818_xfer_msg(adap, &msgs[i], (i == 0), (i == (num - 1)));
|
||||
ret = rockchip_xfer_msg(adap, &msgs[i], (i == 0), (i == (num - 1)));
|
||||
if (ret != 0)
|
||||
{
|
||||
num = ret;
|
||||
dev_err(i2c->dev, "rk2818_xfer_msg error, ret = %d\n", ret);
|
||||
dev_err(i2c->dev, "rockchip_xfer_msg error, ret = %d\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -521,19 +525,19 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap,
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 rk2818_i2c_func(struct i2c_adapter *adap)
|
||||
static u32 rockchip_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm rk2818_i2c_algorithm = {
|
||||
.master_xfer = rk2818_i2c_xfer,
|
||||
.functionality = rk2818_i2c_func,
|
||||
static const struct i2c_algorithm rockchip_i2c_algorithm = {
|
||||
.master_xfer = rockchip_i2c_xfer,
|
||||
.functionality = rockchip_i2c_func,
|
||||
};
|
||||
|
||||
int i2c_suspended(struct i2c_adapter *adap)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
|
||||
struct rockchip_i2c_data *i2c = (struct rockchip_i2c_data *)adap->algo_data;
|
||||
if(adap->nr > 1)
|
||||
return 1;
|
||||
if(i2c == NULL)
|
||||
@@ -542,7 +546,7 @@ int i2c_suspended(struct i2c_adapter *adap)
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_suspended);
|
||||
|
||||
static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c)
|
||||
static void rockchip_i2c_init_hw(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
unsigned long lcmr = 0x00000000;
|
||||
|
||||
@@ -552,9 +556,9 @@ static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c)
|
||||
|
||||
writel(lcmr, i2c->regs + I2C_LCMR);
|
||||
|
||||
rk2818_i2c_disable_irqs(i2c);
|
||||
rockchip_i2c_disable_irqs(i2c);
|
||||
|
||||
rk2818_i2c_clockrate(i2c);
|
||||
rockchip_i2c_clockrate(i2c);
|
||||
|
||||
opr = readl(i2c->regs + I2C_OPR);
|
||||
opr |= I2C_OPR_CORE_ENABLE;
|
||||
@@ -565,12 +569,12 @@ static void rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c)
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
|
||||
#define freq_to_i2c(_n) container_of(_n, struct rk2818_i2c_data, freq_transition)
|
||||
#define freq_to_i2c(_n) container_of(_n, struct rockchip_i2c_data, freq_transition)
|
||||
|
||||
static int rk2818_i2c_cpufreq_transition(struct notifier_block *nb,
|
||||
static int rockchip_i2c_cpufreq_transition(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c = freq_to_i2c(nb);
|
||||
struct rockchip_i2c_data *i2c = freq_to_i2c(nb);
|
||||
unsigned long flags;
|
||||
int delta_f;
|
||||
delta_f = clk_get_rate(i2c->clk) - i2c->i2c_rate;
|
||||
@@ -579,41 +583,45 @@ static int rk2818_i2c_cpufreq_transition(struct notifier_block *nb,
|
||||
(val == CPUFREQ_PRECHANGE && delta_f > 0))
|
||||
{
|
||||
spin_lock_irqsave(&i2c->cmd_lock, flags);
|
||||
rk2818_i2c_clockrate(i2c);
|
||||
rockchip_i2c_clockrate(i2c);
|
||||
spin_unlock_irqrestore(&i2c->cmd_lock, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rk2818_i2c_register_cpufreq(struct rk2818_i2c_data *i2c)
|
||||
static inline int rockchip_i2c_register_cpufreq(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
i2c->freq_transition.notifier_call = rk2818_i2c_cpufreq_transition;
|
||||
i2c->freq_transition.notifier_call = rockchip_i2c_cpufreq_transition;
|
||||
|
||||
return cpufreq_register_notifier(&i2c->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
static inline void rk2818_i2c_unregister_cpufreq(struct rk2818_i2c_data *i2c)
|
||||
static inline void rockchip_i2c_unregister_cpufreq(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
cpufreq_unregister_notifier(&i2c->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int rk2818_i2c_register_cpufreq(struct rk2818_i2c_data *i2c)
|
||||
static inline int rockchip_i2c_register_cpufreq(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rk2818_i2c_unregister_cpufreq(struct rk2818_i2c_data *i2c)
|
||||
static inline void rockchip_i2c_unregister_cpufreq(struct rockchip_i2c_data *i2c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
static int rockchip_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c;
|
||||
struct rk2818_i2c_platform_data *pdata;
|
||||
struct rockchip_i2c_data *i2c;
|
||||
#ifdef CONFIG_ARCH_RK2818
|
||||
struct rk2818_i2c_platform_data *pdata = NULL;
|
||||
#else
|
||||
struct rk29_i2c_platform_data *pdata = NULL;
|
||||
#endif
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
@@ -623,7 +631,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "<error>no platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
i2c = kzalloc(sizeof(struct rk2818_i2c_data), GFP_KERNEL);
|
||||
i2c = kzalloc(sizeof(struct rockchip_i2c_data), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
{
|
||||
dev_err(&pdev->dev, "<error>no memory for state\n");
|
||||
@@ -634,7 +642,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
strlcpy(i2c->adap.name, DRV_NAME, sizeof(i2c->adap.name));
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &rk2818_i2c_algorithm;
|
||||
i2c->adap.algo = &rockchip_i2c_algorithm;
|
||||
i2c->adap.class = I2C_CLASS_HWMON;
|
||||
spin_lock_init(&i2c->cmd_lock);
|
||||
|
||||
@@ -678,7 +686,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
if(pdata->io_init)
|
||||
pdata->io_init();
|
||||
|
||||
rk2818_i2c_init_hw(i2c);
|
||||
rockchip_i2c_init_hw(i2c);
|
||||
|
||||
i2c->irq = ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
@@ -687,7 +695,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
}
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
{
|
||||
ret = request_irq(i2c->irq, rk2818_i2c_irq, IRQF_DISABLED,
|
||||
ret = request_irq(i2c->irq, rockchip_i2c_irq, IRQF_DISABLED,
|
||||
dev_name(&pdev->dev), i2c);
|
||||
|
||||
if (ret != 0) {
|
||||
@@ -695,7 +703,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
goto err_iomap;
|
||||
}
|
||||
}
|
||||
ret = rk2818_i2c_register_cpufreq(i2c);
|
||||
ret = rockchip_i2c_register_cpufreq(i2c);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
|
||||
goto err_irq;
|
||||
@@ -714,7 +722,7 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_cpufreq:
|
||||
rk2818_i2c_unregister_cpufreq(i2c);
|
||||
rockchip_i2c_unregister_cpufreq(i2c);
|
||||
|
||||
err_irq:
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
@@ -737,11 +745,11 @@ static int rk2818_i2c_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
|
||||
static int rk2818_i2c_remove(struct platform_device *pdev)
|
||||
static int rockchip_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
struct rockchip_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
rk2818_i2c_unregister_cpufreq(i2c);
|
||||
rockchip_i2c_unregister_cpufreq(i2c);
|
||||
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
@@ -761,51 +769,51 @@ static int rk2818_i2c_remove(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int rk2818_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int rockchip_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
struct rockchip_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c->suspended = 1;
|
||||
return 0;
|
||||
}
|
||||
static int rk2818_i2c_resume(struct platform_device *pdev)
|
||||
static int rockchip_i2c_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
struct rockchip_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c->suspended = 0;
|
||||
rk2818_i2c_init_hw(i2c);
|
||||
rockchip_i2c_init_hw(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define rk2818_i2c_suspend NULL
|
||||
#define rk2818_i2c_resume NULL
|
||||
#define rockchip_i2c_suspend NULL
|
||||
#define rockchip_i2c_resume NULL
|
||||
#endif
|
||||
|
||||
|
||||
static struct platform_driver rk2818_i2c_driver = {
|
||||
.probe = rk2818_i2c_probe,
|
||||
.remove = rk2818_i2c_remove,
|
||||
.suspend = rk2818_i2c_suspend,
|
||||
.resume = rk2818_i2c_resume,
|
||||
static struct platform_driver rockchip_i2c_driver = {
|
||||
.probe = rockchip_i2c_probe,
|
||||
.remove = rockchip_i2c_remove,
|
||||
.suspend = rockchip_i2c_suspend,
|
||||
.resume = rockchip_i2c_resume,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rk2818_i2c_adap_init(void)
|
||||
static int __init rockchip_i2c_adap_init(void)
|
||||
{
|
||||
return platform_driver_register(&rk2818_i2c_driver);
|
||||
return platform_driver_register(&rockchip_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit rk2818_i2c_adap_exit(void)
|
||||
static void __exit rockchip_i2c_adap_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rk2818_i2c_driver);
|
||||
platform_driver_unregister(&rockchip_i2c_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(rk2818_i2c_adap_init);
|
||||
module_exit(rk2818_i2c_adap_exit);
|
||||
subsys_initcall(rockchip_i2c_adap_init);
|
||||
module_exit(rockchip_i2c_adap_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for RK2818 I2C Bus");
|
||||
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
|
||||
|
||||
821
drivers/i2c/busses/i2c-rk29.c
Executable file
821
drivers/i2c/busses/i2c-rk29.c
Executable file
@@ -0,0 +1,821 @@
|
||||
/* drivers/i2c/busses/i2c_rk29.c
|
||||
*
|
||||
* Copyright (C) 2010 ROCKCHIP, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <mach/board.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "i2c-rk29.h"
|
||||
#define DRV_NAME "rk29_i2c"
|
||||
|
||||
#define RK2818_I2C_TIMEOUT (msecs_to_jiffies(500))
|
||||
#define RK2818_DELAY_TIME 2
|
||||
|
||||
#if 1
|
||||
#define i2c_dbg(dev, format, arg...) \
|
||||
dev_printk(KERN_INFO , dev , format , ## arg)
|
||||
#else
|
||||
#define i2c_dbg(dev, format, arg...)
|
||||
#endif
|
||||
|
||||
enum rk29_error {
|
||||
RK2818_ERROR_NONE = 0,
|
||||
RK2818_ERROR_ARBITR_LOSE,
|
||||
RK2818_ERROR_UNKNOWN
|
||||
};
|
||||
|
||||
enum rk29_event {
|
||||
RK2818_EVENT_NONE = 0,
|
||||
/* master has received ack(MTX mode)
|
||||
means that data has been sent to slave.
|
||||
*/
|
||||
RK2818_EVENT_MTX_RCVD_ACK,
|
||||
/* master needs to send ack to slave(MRX mode)
|
||||
means that data has been received from slave.
|
||||
*/
|
||||
RK2818_EVENT_MRX_NEED_ACK,
|
||||
RK2818_EVENT_MAX
|
||||
};
|
||||
|
||||
struct rk29_i2c_data {
|
||||
struct device *dev;
|
||||
struct i2c_adapter adap;
|
||||
void __iomem *regs;
|
||||
struct resource *ioarea;
|
||||
|
||||
unsigned int suspended:1;
|
||||
unsigned long scl_rate;
|
||||
unsigned long i2c_rate;
|
||||
struct clk *clk;
|
||||
|
||||
unsigned int mode;
|
||||
|
||||
unsigned int irq;
|
||||
|
||||
spinlock_t cmd_lock;
|
||||
struct completion cmd_complete;
|
||||
enum rk29_event cmd_event;
|
||||
enum rk29_error cmd_err;
|
||||
|
||||
unsigned int msg_idx;
|
||||
unsigned int msg_num;
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
struct notifier_block freq_transition;
|
||||
#endif
|
||||
};
|
||||
|
||||
static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c);
|
||||
|
||||
static inline void rk29_i2c_disable_irqs(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
tmp = readl(i2c->regs + I2C_IER);
|
||||
writel(tmp & IRQ_ALL_DISABLE, i2c->regs + I2C_IER);
|
||||
}
|
||||
static inline void rk29_i2c_enable_irqs(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
tmp = readl(i2c->regs + I2C_IER);
|
||||
writel(tmp | IRQ_MST_ENABLE, i2c->regs + I2C_IER);
|
||||
}
|
||||
|
||||
/* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
|
||||
static void rk29_i2c_calcdivisor(unsigned long pclk,
|
||||
unsigned long scl_rate,
|
||||
unsigned long *real_rate,
|
||||
unsigned int *rem, unsigned int *exp)
|
||||
{
|
||||
unsigned int calc_rem = 0;
|
||||
unsigned int calc_exp = 0;
|
||||
|
||||
for(calc_exp = 0; calc_exp < I2CCDVR_EXP_MAX; calc_exp++)
|
||||
{
|
||||
calc_rem = pclk / (5 * scl_rate * (1 <<(calc_exp +1)));
|
||||
if(calc_rem < I2CCDVR_REM_MAX)
|
||||
break;
|
||||
}
|
||||
if(calc_rem >= I2CCDVR_REM_MAX || calc_exp >= I2CCDVR_EXP_MAX)
|
||||
{
|
||||
calc_rem = I2CCDVR_REM_MAX - 1;
|
||||
calc_exp = I2CCDVR_EXP_MAX - 1;
|
||||
}
|
||||
*rem = calc_rem;
|
||||
*exp = calc_exp;
|
||||
*real_rate = pclk/(5 * (calc_rem + 1) * (1 <<(calc_exp +1)));
|
||||
return;
|
||||
}
|
||||
/* set i2c bus scl rate */
|
||||
static void rk29_i2c_clockrate(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_RK2818
|
||||
struct rk2818_i2c_platform_data *pdata = i2c->dev->platform_data;
|
||||
#else
|
||||
struct rk29_i2c_platform_data *pdata = i2c->dev->platform_data;
|
||||
#endif
|
||||
unsigned int rem = 0, exp = 0;
|
||||
unsigned long scl_rate, real_rate = 0, tmp;
|
||||
|
||||
i2c->i2c_rate = clk_get_rate(i2c->clk);
|
||||
|
||||
scl_rate = (i2c->scl_rate) ? i2c->scl_rate : ((pdata->scl_rate)? pdata->scl_rate:100000);
|
||||
|
||||
rk29_i2c_calcdivisor(i2c->i2c_rate, scl_rate, &real_rate, &rem, &exp);
|
||||
|
||||
tmp = readl(i2c->regs + I2C_OPR);
|
||||
tmp |= exp;
|
||||
tmp |= rem<<I2CCDVR_EXP_BITS;
|
||||
writel(tmp, i2c->regs + I2C_OPR);
|
||||
if(real_rate > 400000)
|
||||
dev_warn(i2c->dev, "i2c_rate[%luKhz], scl_rate[%luKhz], real_rate[%luKhz] > 400Khz\n",
|
||||
i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
|
||||
else
|
||||
i2c_dbg(i2c->dev, "i2c_rate[%luKhz], scl_rate[%luKhz], real_rate[%luKhz]\n",
|
||||
i2c->i2c_rate/1000, scl_rate/1000, real_rate/1000);
|
||||
return;
|
||||
}
|
||||
static int rk29_event_occurred(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
unsigned long isr;
|
||||
|
||||
isr = readl(i2c->regs + I2C_ISR);
|
||||
i2c_dbg(i2c->dev,"event occurred, isr = %lx\n", isr);
|
||||
if(isr & I2C_ISR_ARBITR_LOSE)
|
||||
{
|
||||
isr &= ~I2C_ISR_ARBITR_LOSE;
|
||||
writel(isr, i2c->regs + I2C_ISR);
|
||||
i2c->cmd_err = RK2818_ERROR_ARBITR_LOSE;
|
||||
dev_err(i2c->dev, "<error>arbitration loss\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch(i2c->cmd_event)
|
||||
{
|
||||
case RK2818_EVENT_MTX_RCVD_ACK:
|
||||
if(isr & I2C_ISR_MTX_RCVD_ACK)
|
||||
{
|
||||
isr &= ~I2C_ISR_MTX_RCVD_ACK;
|
||||
writel(isr, i2c->regs + I2C_ISR);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case RK2818_EVENT_MRX_NEED_ACK:
|
||||
if(isr & I2C_ISR_MRX_NEED_ACK)
|
||||
{
|
||||
isr &= ~I2C_ISR_MRX_NEED_ACK;
|
||||
writel(isr, i2c->regs + I2C_ISR);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i2c->cmd_err = RK2818_ERROR_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t rk29_i2c_irq(int irq, void *data)
|
||||
{
|
||||
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)data;
|
||||
int res;
|
||||
|
||||
rk29_i2c_disable_irqs(i2c);
|
||||
spin_lock(&i2c->cmd_lock);
|
||||
res = rk29_event_occurred(i2c);
|
||||
if(res)
|
||||
//if(res || i2c->cmd_err != RK2818_ERROR_NONE)
|
||||
complete(&i2c->cmd_complete);
|
||||
spin_unlock(&i2c->cmd_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
static int wait_for_completion_poll_timeout(struct rk29_i2c_data *i2c, unsigned long timeout)
|
||||
{
|
||||
unsigned int time = RK2818_DELAY_TIME;
|
||||
int res;
|
||||
|
||||
while(!time_after(jiffies, jiffies + timeout))
|
||||
{
|
||||
res = rk29_event_occurred(i2c);
|
||||
if(res)
|
||||
//if(res || (i2c->cmd_err != RK2818_ERROR_NONE && i2c->cmd_err != RK2818_ERROR_UNKNOWN))
|
||||
return 1;
|
||||
udelay(time);
|
||||
time *= 2;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
static int rk29_wait_event(struct rk29_i2c_data *i2c,
|
||||
enum rk29_event mr_event)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
{
|
||||
if(unlikely(irqs_disabled()))
|
||||
{
|
||||
dev_err(i2c->dev, "irqs are disabled on this system!\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
spin_lock_irqsave(&i2c->cmd_lock,flags);
|
||||
i2c->cmd_err = RK2818_ERROR_NONE;
|
||||
i2c->cmd_event = mr_event;
|
||||
|
||||
init_completion(&i2c->cmd_complete);
|
||||
|
||||
spin_unlock_irqrestore(&i2c->cmd_lock,flags);
|
||||
|
||||
rk29_i2c_enable_irqs(i2c);
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
|
||||
RK2818_I2C_TIMEOUT);
|
||||
else
|
||||
ret = wait_for_completion_poll_timeout(i2c, RK2818_I2C_TIMEOUT);
|
||||
|
||||
if(ret < 0)
|
||||
{
|
||||
dev_err(i2c->dev, "i2c wait for event %04x, retrun %d \n", mr_event, ret);
|
||||
return ret;
|
||||
}
|
||||
if(ret == 0)
|
||||
{
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk29_wait_while_busy(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
|
||||
unsigned long lsr;
|
||||
unsigned int time = RK2818_DELAY_TIME;
|
||||
|
||||
while(!time_after(jiffies, timeout))
|
||||
{
|
||||
lsr = readl(i2c->regs + I2C_LSR);
|
||||
if(!(lsr & I2C_LSR_BUSY))
|
||||
return 0;
|
||||
udelay(time);
|
||||
time *= 2;
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
static int rk29_i2c_stop(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
|
||||
unsigned int time = RK2818_DELAY_TIME;
|
||||
|
||||
writel(I2C_LCMR_STOP|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
while(!time_after(jiffies, timeout))
|
||||
{
|
||||
if(!(readl(i2c->regs + I2C_LCMR) & I2C_LCMR_STOP))
|
||||
{
|
||||
i2c_dbg(i2c->dev, "i2c stop successfully\n");
|
||||
return 0;
|
||||
}
|
||||
udelay(time);
|
||||
time *= 2;
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
|
||||
}
|
||||
static int rk29_send_2nd_addr(struct rk29_i2c_data *i2c,
|
||||
struct i2c_msg *msg, int start)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long addr_2nd = msg->addr & 0xff;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
|
||||
conr |= I2C_CONR_MTX_MODE;
|
||||
//conr &= I2C_CONR_ACK;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
|
||||
i2c_dbg(i2c->dev, "i2c send addr_2nd: %lx\n", addr_2nd);
|
||||
writel(addr_2nd, i2c->regs + I2C_MTXR);
|
||||
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "after sent addr_2nd, i2c wait for ACK timeout\n");
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rk29_send_address(struct rk29_i2c_data *i2c,
|
||||
struct i2c_msg *msg, int start)
|
||||
{
|
||||
unsigned long addr_1st;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
int ret = 0;
|
||||
|
||||
if(msg->flags & I2C_M_TEN)
|
||||
addr_1st = (0xf0 | (((unsigned long) msg->addr & 0x300) >> 7)) & 0xff;
|
||||
else
|
||||
addr_1st = ((msg->addr << 1) & 0xff);
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
addr_1st |= 0x01;
|
||||
else
|
||||
addr_1st &= (~0x01);
|
||||
|
||||
conr |= I2C_CONR_MTX_MODE;
|
||||
//conr &= I2C_CONR_ACK;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
i2c_dbg(i2c->dev, "i2c send addr_1st: %lx\n", addr_1st);
|
||||
|
||||
writel(addr_1st, i2c->regs + I2C_MTXR);
|
||||
|
||||
if (start)
|
||||
{
|
||||
if((ret = rk29_wait_while_busy(i2c)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "i2c is busy, when send address\n");
|
||||
return ret;
|
||||
}
|
||||
writel(I2C_LCMR_START, i2c->regs + I2C_LCMR);
|
||||
}
|
||||
else
|
||||
writel(I2C_LCMR_START|I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
|
||||
if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "after sent addr_1st, i2c wait for ACK timeout\n");
|
||||
return ret;
|
||||
}
|
||||
if(start && (msg->flags & I2C_M_TEN))
|
||||
ret = rk29_send_2nd_addr(i2c, msg, start);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk29_i2c_send_msg(struct rk29_i2c_data *i2c, struct i2c_msg *msg)
|
||||
{
|
||||
int i, ret = 0;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr |= I2C_CONR_MTX_MODE;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
for(i = 0; i < msg->len; i++)
|
||||
{
|
||||
i2c_dbg(i2c->dev, "i2c send buf[%d]: %x\n", i, msg->buf[i]);
|
||||
writel(msg->buf[i], i2c->regs + I2C_MTXR);
|
||||
/*
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr &= I2C_CONR_ACK;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
*/
|
||||
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
|
||||
if((ret = rk29_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK)) != 0)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rk29_i2c_recv_msg(struct rk29_i2c_data *i2c, struct i2c_msg *msg)
|
||||
{
|
||||
int i, ret = 0;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr &= I2C_CONR_MRX_MODE;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
|
||||
for(i = 0; i < msg->len; i++)
|
||||
{
|
||||
writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
|
||||
if((ret = rk29_wait_event(i2c, RK2818_EVENT_MRX_NEED_ACK)) != 0)
|
||||
return ret;
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr &= I2C_CONR_ACK;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
msg->buf[i] = (uint8_t)readl(i2c->regs + I2C_MRXR);
|
||||
i2c_dbg(i2c->dev, "i2c recv >>>>>>>>>>>> buf[%d]: %x\n", i, msg->buf[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int rk29_xfer_msg(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, int start, int stop)
|
||||
{
|
||||
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
int ret = 0;
|
||||
|
||||
#if defined (CONFIG_IOEXTEND_TCA6424)
|
||||
struct tca6424_platform_data *pdata = adap->dev.platform_data;
|
||||
#endif
|
||||
|
||||
if(msg->len == 0)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
dev_err(i2c->dev, "<error>msg->len = %d\n", msg->len);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if((ret = rk29_send_address(i2c, msg, start))!= 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk29_send_address timeout\n");
|
||||
goto exit;
|
||||
}
|
||||
if(msg->flags & I2C_M_RD)
|
||||
{
|
||||
if((ret = rk29_i2c_recv_msg(i2c, msg)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk29_i2c_recv_msg timeout\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((ret = rk29_i2c_send_msg(i2c, msg)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk29_i2c_send_msg timeout\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if(stop)
|
||||
{
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr |= I2C_CONR_NAK;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
if((ret = rk29_i2c_stop(i2c)) != 0)
|
||||
{
|
||||
dev_err(i2c->dev, "<error>rk29_i2c_stop timeout\n");
|
||||
}
|
||||
#if 0
|
||||
//not I2C code,add by sxj,used for extend gpio intrrupt,set SCL and SDA pin.
|
||||
if(msg->flags & I2C_M_RD)
|
||||
{
|
||||
#if defined (CONFIG_IOEXTEND_TCA6424)
|
||||
if (pdata && pdata->reseti2cpin) {
|
||||
pdata->reseti2cpin();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int rk29_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
int ret = -1;
|
||||
int i;
|
||||
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
|
||||
unsigned long conr = readl(i2c->regs + I2C_CONR);
|
||||
/*
|
||||
if(i2c->suspended ==1)
|
||||
return -EIO;
|
||||
*/
|
||||
if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate > 0)
|
||||
i2c->scl_rate = msgs[0].scl_rate;
|
||||
else
|
||||
i2c->scl_rate = 400000;
|
||||
|
||||
conr |= I2C_CONR_MPORT_ENABLE;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
|
||||
rk29_i2c_init_hw(i2c);
|
||||
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr &= I2C_CONR_ACK;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
ret = rk29_xfer_msg(adap, &msgs[i], (i == 0), (i == (num - 1)));
|
||||
if (ret != 0)
|
||||
{
|
||||
num = ret;
|
||||
dev_err(i2c->dev, "rk29_xfer_msg error, ret = %d\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
conr = readl(i2c->regs + I2C_CONR);
|
||||
conr &= I2C_CONR_MPORT_DISABLE;
|
||||
writel(conr, i2c->regs + I2C_CONR);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 rk29_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm rk29_i2c_algorithm = {
|
||||
.master_xfer = rk29_i2c_xfer,
|
||||
.functionality = rk29_i2c_func,
|
||||
};
|
||||
|
||||
int i2c_suspended(struct i2c_adapter *adap)
|
||||
{
|
||||
struct rk29_i2c_data *i2c = (struct rk29_i2c_data *)adap->algo_data;
|
||||
if(adap->nr > 1)
|
||||
return 1;
|
||||
if(i2c == NULL)
|
||||
return 1;
|
||||
return i2c->suspended;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_suspended);
|
||||
|
||||
static void rk29_i2c_init_hw(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
unsigned long lcmr = 0x00000000;
|
||||
|
||||
unsigned long opr = readl(i2c->regs + I2C_OPR);
|
||||
opr |= I2C_OPR_RESET_STATUS;
|
||||
writel(opr, i2c->regs + I2C_OPR);
|
||||
|
||||
writel(lcmr, i2c->regs + I2C_LCMR);
|
||||
|
||||
rk29_i2c_disable_irqs(i2c);
|
||||
|
||||
rk29_i2c_clockrate(i2c);
|
||||
|
||||
opr = readl(i2c->regs + I2C_OPR);
|
||||
opr |= I2C_OPR_CORE_ENABLE;
|
||||
writel(opr, i2c->regs + I2C_OPR);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
|
||||
#define freq_to_i2c(_n) container_of(_n, struct rk29_i2c_data, freq_transition)
|
||||
|
||||
static int rk29_i2c_cpufreq_transition(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
struct rk29_i2c_data *i2c = freq_to_i2c(nb);
|
||||
unsigned long flags;
|
||||
int delta_f;
|
||||
delta_f = clk_get_rate(i2c->clk) - i2c->i2c_rate;
|
||||
|
||||
if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
|
||||
(val == CPUFREQ_PRECHANGE && delta_f > 0))
|
||||
{
|
||||
spin_lock_irqsave(&i2c->cmd_lock, flags);
|
||||
rk29_i2c_clockrate(i2c);
|
||||
spin_unlock_irqrestore(&i2c->cmd_lock, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rk29_i2c_register_cpufreq(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
i2c->freq_transition.notifier_call = rk29_i2c_cpufreq_transition;
|
||||
|
||||
return cpufreq_register_notifier(&i2c->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
static inline void rk29_i2c_unregister_cpufreq(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
cpufreq_unregister_notifier(&i2c->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int rk29_i2c_register_cpufreq(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rk29_i2c_unregister_cpufreq(struct rk29_i2c_data *i2c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rk29_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk29_i2c_data *i2c;
|
||||
#ifdef CONFIG_ARCH_RK2818
|
||||
struct rk2818_i2c_platform_data *pdata = NULL;
|
||||
#else
|
||||
struct rk29_i2c_platform_data *pdata = NULL;
|
||||
#endif
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata)
|
||||
{
|
||||
dev_err(&pdev->dev, "<error>no platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
i2c = kzalloc(sizeof(struct rk29_i2c_data), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
{
|
||||
dev_err(&pdev->dev, "<error>no memory for state\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
i2c->mode = pdata->mode;
|
||||
i2c->scl_rate = (pdata->scl_rate) ? pdata->scl_rate : 100000;
|
||||
|
||||
strlcpy(i2c->adap.name, DRV_NAME, sizeof(i2c->adap.name));
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &rk29_i2c_algorithm;
|
||||
i2c->adap.class = I2C_CLASS_HWMON;
|
||||
spin_lock_init(&i2c->cmd_lock);
|
||||
|
||||
i2c->dev = &pdev->dev;
|
||||
|
||||
i2c->clk = clk_get(&pdev->dev, "i2c");
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
dev_err(&pdev->dev, "<error>cannot get clock\n");
|
||||
ret = -ENOENT;
|
||||
goto err_noclk;
|
||||
}
|
||||
|
||||
clk_enable(i2c->clk);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "<error>cannot find IO resource\n");
|
||||
ret = -ENOENT;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
i2c->ioarea = request_mem_region(res->start, res->end - res->start + 1,
|
||||
pdev->name);
|
||||
|
||||
if (i2c->ioarea == NULL) {
|
||||
dev_err(&pdev->dev, "<error>cannot request IO\n");
|
||||
ret = -ENXIO;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
i2c->regs = ioremap(res->start, res->end - res->start + 1);
|
||||
|
||||
if (i2c->regs == NULL) {
|
||||
dev_err(&pdev->dev, "<error>annot map IO\n");
|
||||
ret = -ENXIO;
|
||||
goto err_ioarea;
|
||||
}
|
||||
i2c->adap.algo_data = i2c;
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
|
||||
if(pdata->io_init)
|
||||
pdata->io_init();
|
||||
|
||||
rk29_i2c_init_hw(i2c);
|
||||
|
||||
i2c->irq = ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "cannot find IRQ\n");
|
||||
goto err_iomap;
|
||||
}
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
{
|
||||
ret = request_irq(i2c->irq, rk29_i2c_irq, IRQF_DISABLED,
|
||||
dev_name(&pdev->dev), i2c);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
|
||||
goto err_iomap;
|
||||
}
|
||||
}
|
||||
ret = rk29_i2c_register_cpufreq(i2c);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
i2c->adap.nr = pdata->bus_num;
|
||||
ret = i2c_add_numbered_adapter(&i2c->adap);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
|
||||
goto err_cpufreq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
dev_info(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev));
|
||||
return 0;
|
||||
|
||||
err_cpufreq:
|
||||
rk29_i2c_unregister_cpufreq(i2c);
|
||||
|
||||
err_irq:
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
free_irq(i2c->irq, i2c);
|
||||
|
||||
err_iomap:
|
||||
iounmap(i2c->regs);
|
||||
|
||||
err_ioarea:
|
||||
release_resource(i2c->ioarea);
|
||||
kfree(i2c->ioarea);
|
||||
|
||||
err_clk:
|
||||
clk_disable(i2c->clk);
|
||||
clk_put(i2c->clk);
|
||||
|
||||
err_noclk:
|
||||
kfree(i2c);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int rk29_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
rk29_i2c_unregister_cpufreq(i2c);
|
||||
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
if(i2c->mode == I2C_MODE_IRQ)
|
||||
free_irq(i2c->irq, i2c);
|
||||
|
||||
clk_disable(i2c->clk);
|
||||
clk_put(i2c->clk);
|
||||
|
||||
iounmap(i2c->regs);
|
||||
|
||||
release_resource(i2c->ioarea);
|
||||
kfree(i2c->ioarea);
|
||||
kfree(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int rk29_i2c_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c->suspended = 1;
|
||||
return 0;
|
||||
}
|
||||
static int rk29_i2c_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct rk29_i2c_data *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c->suspended = 0;
|
||||
rk29_i2c_init_hw(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define rk29_i2c_suspend NULL
|
||||
#define rk29_i2c_resume NULL
|
||||
#endif
|
||||
|
||||
|
||||
static struct platform_driver rk29_i2c_driver = {
|
||||
.probe = rk29_i2c_probe,
|
||||
.remove = rk29_i2c_remove,
|
||||
.suspend = rk29_i2c_suspend,
|
||||
.resume = rk29_i2c_resume,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rk29_i2c_adap_init(void)
|
||||
{
|
||||
return platform_driver_register(&rk29_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit rk29_i2c_adap_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rk29_i2c_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(rk29_i2c_adap_init);
|
||||
module_exit(rk29_i2c_adap_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for RK2818 I2C Bus");
|
||||
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
|
||||
73
drivers/i2c/busses/i2c-rk29.h
Executable file
73
drivers/i2c/busses/i2c-rk29.h
Executable file
@@ -0,0 +1,73 @@
|
||||
/* drivers/i2c/busses/i2c_rk2818.h
|
||||
*
|
||||
* Copyright (C) 2010 ROCKCHIP, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RK2818_I2C_H
|
||||
#define __RK2818_I2C_H
|
||||
|
||||
/* master transmit */
|
||||
#define I2C_MTXR (0x0000)
|
||||
/* master receive */
|
||||
#define I2C_MRXR (0x0004)
|
||||
/* slave address */
|
||||
#define I2C_SADDR (0x0010)
|
||||
/* interrupt enable control */
|
||||
#define I2C_IER (0x0014)
|
||||
#define I2C_IER_ARBITR_LOSE (1<<7)
|
||||
#define I2C_IER_MRX_NEED_ACK (1<<1)
|
||||
#define I2C_IER_MTX_RCVD_ACK (1<<0)
|
||||
|
||||
#define IRQ_MST_ENABLE (I2C_IER_ARBITR_LOSE | \
|
||||
I2C_IER_MRX_NEED_ACK | \
|
||||
I2C_IER_MTX_RCVD_ACK)
|
||||
#define IRQ_ALL_DISABLE (0x00)
|
||||
|
||||
/* interrupt status, write 0 to clear */
|
||||
#define I2C_ISR (0x0018)
|
||||
#define I2C_ISR_ARBITR_LOSE (1<<7)
|
||||
#define I2C_ISR_MRX_NEED_ACK (1<<1)
|
||||
#define I2C_ISR_MTX_RCVD_ACK (1<<0)
|
||||
|
||||
/* stop/start/resume command, write 1 to set */
|
||||
#define I2C_LCMR (0x001c)
|
||||
#define I2C_LCMR_RESUME (1<<2)
|
||||
#define I2C_LCMR_STOP (1<<1)
|
||||
#define I2C_LCMR_START (1<<0)
|
||||
|
||||
/* i2c core status */
|
||||
#define I2C_LSR (0x0020)
|
||||
#define I2C_LSR_RCV_NAK (1<<1)
|
||||
#define I2C_LSR_RCV_ACK (~(1<<1))
|
||||
#define I2C_LSR_BUSY (1<<0)
|
||||
|
||||
/* i2c config */
|
||||
#define I2C_CONR (0x0024)
|
||||
#define I2C_CONR_NAK (1<<4)
|
||||
#define I2C_CONR_ACK (~(1<<4))
|
||||
#define I2C_CONR_MTX_MODE (1<<3)
|
||||
#define I2C_CONR_MRX_MODE (~(1<<3))
|
||||
#define I2C_CONR_MPORT_ENABLE (1<<2)
|
||||
#define I2C_CONR_MPORT_DISABLE (~(1<<2))
|
||||
|
||||
/* i2c core config */
|
||||
#define I2C_OPR (0x0028)
|
||||
#define I2C_OPR_RESET_STATUS (1<<7)
|
||||
#define I2C_OPR_CORE_ENABLE (1<<6)
|
||||
|
||||
#define I2CCDVR_REM_BITS (0x03)
|
||||
#define I2CCDVR_REM_MAX (1<<(I2CCDVR_REM_BITS))
|
||||
#define I2CCDVR_EXP_BITS (0x03)
|
||||
#define I2CCDVR_EXP_MAX (1<<(I2CCDVR_EXP_BITS))
|
||||
|
||||
#endif
|
||||
@@ -1091,7 +1091,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_I2C_RK2818
|
||||
#if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29)
|
||||
if (!(i2c_suspended(adap)) && (in_atomic() || irqs_disabled())) {
|
||||
#else
|
||||
if (in_atomic() || irqs_disabled()) {
|
||||
@@ -1123,7 +1123,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_transfer);
|
||||
#if defined (CONFIG_I2C_RK2818)
|
||||
#if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29)
|
||||
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -54,7 +54,7 @@ struct i2c_board_info;
|
||||
* transmit one message at a time, a more complex version can be used to
|
||||
* transmit an arbitrary number of messages without interruption.
|
||||
*/
|
||||
#if defined (CONFIG_I2C_RK2818)
|
||||
#if defined (CONFIG_I2C_RK2818) || defined(CONFIG_I2C_RK29)
|
||||
/* If everything went ok, return 'count' transmitted, else error code. */
|
||||
extern int i2c_master_normal_send(struct i2c_client *client,const char *buf ,int count, int scl_rate);
|
||||
extern int i2c_master_normal_recv(struct i2c_client *client, char *buf ,int count, int scl_rate);
|
||||
|
||||
Reference in New Issue
Block a user