summaryrefslogtreecommitdiff
path: root/arch/arm/plat-aspeed/dev-i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-aspeed/dev-i2c.c')
-rw-r--r--arch/arm/plat-aspeed/dev-i2c.c669
1 files changed, 669 insertions, 0 deletions
diff --git a/arch/arm/plat-aspeed/dev-i2c.c b/arch/arm/plat-aspeed/dev-i2c.c
new file mode 100644
index 000000000000..47cd15249b10
--- /dev/null
+++ b/arch/arm/plat-aspeed/dev-i2c.c
@@ -0,0 +1,669 @@
+/********************************************************************************
+* File Name : linux/arch/arm/plat-aspeed/dev-i2c.c
+* Author : Ryan chen
+* Description : ASPEED I2C Device
+*
+* Copyright (C) ASPEED Technology Inc.
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by the Free Software Foundation;
+* either version 2 of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+* History :
+* 1. 2012/07/30 ryan chen create this file
+*
+********************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <asm/io.h>
+#include <mach/irqs.h>
+#include <mach/platform.h>
+#include <plat/ast_i2c.h>
+#include <plat/devs.h>
+#include <plat/regs-iic.h>
+#include <plat/ast-scu.h>
+
+/* --------------------------------------------------------------------
+ * I2C
+ * -------------------------------------------------------------------- */
+#ifdef AST_I2C_DEBUG
+#define I2CDBUG(fmt, args...) printk("%s() " fmt, __FUNCTION__, ## args)
+#else
+#define I2CDBUG(fmt, args...)
+#endif
+
+#if defined(CONFIG_I2C_AST) || defined(CONFIG_I2C_AST_MODULE)
+
+#if defined (CONFIG_ARCH_AST2400)
+#define I2C_PAGE_SIZE 8
+struct buf_page page_info[I2C_PAGE_SIZE] =
+{
+ [0] = {
+ .flag = 0,
+ .page_no = 0,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+ [1] = {
+ .flag = 0,
+ .page_no = 1,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+ [2] = {
+ .flag = 0,
+ .page_no = 2,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+ [3] = {
+ .flag = 0,
+ .page_no = 3,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+ [4] = {
+ .flag = 0,
+ .page_no = 4,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+ [5] = {
+ .flag = 0,
+ .page_no = 5,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+ [6] = {
+ .flag = 0,
+ .page_no = 6,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+ [7] = {
+ .flag = 0,
+ .page_no = 7,
+ .page_size = 256,
+ .page_addr_point = 0,
+ },
+};
+
+static void pool_buff_page_init(u32 buf_pool_addr)
+{
+ u32 offset;
+ int i ,j;
+
+ for(i=0;i<I2C_PAGE_SIZE;i++) {
+ offset = 0;
+ for(j=0;j<i;j++)
+ offset += page_info[i].page_size;
+
+ page_info[i].page_addr = buf_pool_addr + offset;
+// I2CDBUG( "page[%d],addr :%x \n", i, page_info[i].page_addr);
+ }
+
+}
+
+static u8 request_pool_buff_page(struct buf_page **req_page)
+{
+ int i;
+ //TODO
+ spinlock_t lock;
+ spin_lock(&lock);
+ for(i=0;i<I2C_PAGE_SIZE;i++) {
+ if(page_info[i].flag ==0) {
+ page_info[i].flag = 1;
+ *req_page = &page_info[i];
+// I2CDBUG( "request page addr %x \n", page_info[i].page_addr);
+ break;
+ }
+ }
+ spin_unlock(&lock);
+ return 0;
+}
+
+static void free_pool_buff_page(struct buf_page *req_page)
+{
+ req_page->flag = 0;
+// I2CDBUG( "free page addr %x \n", req_page->page_addr);
+ req_page = NULL;
+}
+
+#elif defined (CONFIG_ARCH_AST2300)
+#define I2C_PAGE_SIZE 5
+
+struct buf_page page_info[I2C_PAGE_SIZE] =
+{
+ [0] = {
+ .flag = 0,
+ .page_size = 128,
+ },
+ [1] = {
+ .flag = 0,
+ .page_size = 32,
+ },
+ [2] = {
+ .flag = 0,
+ .page_size = 32,
+ },
+ [3] = {
+ .flag = 0,
+ .page_size = 32,
+ },
+ [4] = {
+ .flag = 0,
+ .page_size = 32,
+ },
+};
+
+static void pool_buff_page_init(u32 buf_pool_addr)
+{
+
+ u32 offset;
+ int i ,j;
+
+ for(i=0;i<I2C_PAGE_SIZE;i++) {
+ offset = 0;
+ for(j=0;j<i;j++)
+ offset += page_info[i].page_size;
+
+ page_info[i].page_addr = buf_pool_addr + offset;
+ page_info[i].page_addr_point = page_info[i].page_addr/4;
+// printk("page[%d],addr :%x , point : %d\n", i, page_info[i].page_addr, page_info[i].page_addr_point);
+ }
+}
+
+static u8 request_pool_buff_page(struct buf_page **req_page)
+{
+ int i;
+ //TODO
+ spinlock_t lock;
+ spin_lock(&lock);
+ for(i=0;i<I2C_PAGE_SIZE;i++) {
+ if(page_info[i].flag ==0) {
+ page_info[i].flag = 1;
+ *req_page = &page_info[i];
+ spin_unlock(&lock);
+ return 1;
+ }
+ }
+ spin_unlock(&lock);
+ return 0;
+
+}
+
+//TODO check free ?
+static void free_pool_buff_page(struct buf_page *req_page)
+{
+ req_page->flag = 0;
+ req_page = NULL;
+}
+
+#else
+//DO nothing
+static void pool_buff_page_init(void) {}
+static u8 request_pool_buff_page(struct buf_page **req_page) {return 0;}
+static void free_pool_buff_page(struct buf_page *req_page) {}
+#endif
+
+static struct ast_i2c_driver_data ast_i2c_data = {
+ .bus_clk = 100000, //bus clock 100KHz
+ .master_dma = BUFF_MODE,
+ .slave_dma = BYTE_MODE,
+ .request_pool_buff_page = request_pool_buff_page,
+ .free_pool_buff_page = free_pool_buff_page,
+#ifdef CONFIG_AST_I2C_SLAVE_MODE
+ .slave_xfer = i2c_slave_xfer,
+ .slave_init = i2c_slave_init,
+#endif
+ .get_i2c_clock = ast_get_pclk,
+};
+
+static u64 ast_i2c_dma_mask = 0xffffffffUL;
+static struct resource ast_i2c_dev1_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE1,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE1 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev1_device = {
+ .name = "ast-i2c",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev1_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev1_resources),
+};
+
+static struct resource ast_i2c_dev2_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE2,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE2 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev2_device = {
+ .name = "ast-i2c",
+ .id = 1,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev2_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev2_resources),
+};
+
+static struct resource ast_i2c_dev3_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE3,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE3 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev3_device = {
+ .name = "ast-i2c",
+ .id = 2,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev3_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev3_resources),
+};
+
+static struct resource ast_i2c_dev4_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE4,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE4 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev4_device = {
+ .name = "ast-i2c",
+ .id = 3,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev4_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev4_resources),
+};
+
+static struct resource ast_i2c_dev5_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE5,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE5 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev5_device = {
+ .name = "ast-i2c",
+ .id = 4,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev5_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev5_resources),
+};
+
+static struct resource ast_i2c_dev6_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE6,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE6 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev6_device = {
+ .name = "ast-i2c",
+ .id = 5,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev6_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev6_resources),
+};
+
+static struct resource ast_i2c_dev7_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE7,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE7 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev7_device = {
+ .name = "ast-i2c",
+ .id = 6,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev7_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev7_resources),
+};
+
+static struct resource ast_i2c_dev8_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE8,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE8 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev8_device = {
+ .name = "ast-i2c",
+ .id = 7,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev8_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev8_resources),
+};
+
+static struct resource ast_i2c_dev9_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE9,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE9 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev9_device = {
+ .name = "ast-i2c",
+ .id = 8,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev9_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev9_resources),
+};
+
+#if defined(CONFIG_ARCH_AST2400)
+static struct resource ast_i2c_dev10_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE10,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE10 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev10_device = {
+ .name = "ast-i2c",
+ .id = 9,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev10_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev10_resources),
+};
+
+static struct resource ast_i2c_dev11_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE11,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE11 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev11_device = {
+ .name = "ast-i2c",
+ .id = 10,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev11_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev11_resources),
+};
+
+static struct resource ast_i2c_dev12_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE12,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE12 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev12_device = {
+ .name = "ast-i2c",
+ .id = 11,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev12_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev12_resources),
+};
+
+static struct resource ast_i2c_dev13_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE13,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE13 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev13_device = {
+ .name = "ast-i2c",
+ .id = 12,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev13_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev13_resources),
+};
+
+static struct resource ast_i2c_dev14_resources[] = {
+ [0] = {
+ .start = AST_I2C_BASE + AST_I2C_DEVICE14,
+ .end = AST_I2C_BASE + AST_I2C_DEVICE14 + 4*SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ast_i2c_dev14_device = {
+ .name = "ast-i2c",
+ .id = 13,
+ .dev = {
+ .dma_mask = &ast_i2c_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ast_i2c_data,
+ },
+ .resource = ast_i2c_dev14_resources,
+ .num_resources = ARRAY_SIZE(ast_i2c_dev14_resources),
+};
+#endif
+
+/*--------- I2C Board devices ------------*/
+//ASPEED AST2300 EVB I2C Device
+#if defined(CONFIG_ARCH_AST2300) || defined(CONFIG_ARCH_AST2400)
+//Under I2C Dev 1
+static struct i2c_board_info __initdata ast_i2c_board_info_1[] = {
+ {
+ I2C_BOARD_INFO("cat9883", 0x4d),
+ }
+};
+
+//Under I2C Dev 4
+static struct i2c_board_info __initdata ast_i2c_board_info_4[] = {
+ {
+ I2C_BOARD_INFO("24c128", 0x50),
+
+
+ }
+};
+//Under I2C Dev 8
+static struct i2c_board_info __initdata ast_i2c_board_info_8[] = {
+ {
+ I2C_BOARD_INFO("lm75b", 0x4a),
+ }
+};
+
+#endif
+
+/*-------------------------------------*/
+void __init ast_add_device_i2c(void)
+{
+ //I2C Multi-Pin
+ ast_scu_multi_func_i2c();
+
+ //SCU I2C Reset
+ ast_scu_init_i2c();
+
+ ast_i2c_data.reg_gr = ioremap(AST_I2C_BASE, 4*SZ_16);
+ if (!ast_i2c_data.reg_gr) {
+ printk("ast_add_device_i2c ERROR \n");
+ return;
+ }
+
+#if defined (CONFIG_ARCH_AST2400)
+ ast_i2c_data.buf_pool= ioremap(AST_I2C_BASE+0x800, 2048);
+ if (!ast_i2c_data.buf_pool) {
+ printk("ast_add_device_i2c ERROR \n");
+ return;
+ }
+#else
+ ast_i2c_data.buf_pool = ioremap(AST_I2C_BASE+0x200, 256);
+ if (!ast_i2c_data.buf_pool) {
+ printk("ast_add_device_i2c ERROR \n");
+ return;
+ }
+#endif
+ //TODO
+ pool_buff_page_init(ast_i2c_data.buf_pool);
+ platform_device_register(&ast_i2c_dev1_device);
+ i2c_register_board_info(0, ast_i2c_board_info_1, ARRAY_SIZE(ast_i2c_board_info_1));
+ platform_device_register(&ast_i2c_dev2_device);
+ platform_device_register(&ast_i2c_dev3_device);
+ platform_device_register(&ast_i2c_dev4_device);
+ i2c_register_board_info(3, ast_i2c_board_info_4, ARRAY_SIZE(ast_i2c_board_info_4));
+ platform_device_register(&ast_i2c_dev5_device);
+ platform_device_register(&ast_i2c_dev6_device);
+ platform_device_register(&ast_i2c_dev7_device);
+ platform_device_register(&ast_i2c_dev8_device);
+ i2c_register_board_info(7, ast_i2c_board_info_8, ARRAY_SIZE(ast_i2c_board_info_8));
+ platform_device_register(&ast_i2c_dev9_device);
+
+#if defined(CONFIG_ARCH_AST2400)
+ platform_device_register(&ast_i2c_dev10_device);
+#if defined(CONFIG_MMC_AST)
+ //Due to share pin with SD
+#else
+ platform_device_register(&ast_i2c_dev11_device);
+ platform_device_register(&ast_i2c_dev12_device);
+ platform_device_register(&ast_i2c_dev13_device);
+ platform_device_register(&ast_i2c_dev14_device);
+#endif
+#endif
+}
+#else
+void __init ast_add_device_i2c(void) {}
+#endif