[RESUBMIT][PATCH][RFC] OMAP4: I2C Support for OMAP4430

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds OMAP4 support to the I2C driver. All I2C register addresses
are different between OMAP1/2/3 and OMAP4. In order to not have #ifdef's at
various places in code, as well as to support multi-OMAP build, Array's are
created to hold the register addresses.

Signed-off-by: Syed Rafiuddin <rafiuddin.syed@xxxxxx>
---
 arch/arm/plat-omap/i2c.c      |   22 ++++-
 drivers/i2c/busses/i2c-omap.c |  156 +++++++++++++++++++++++++++++++++---------
 2 files changed, 142 insertions(+), 36 deletions(-)

Index: kernel-omap4-base/arch/arm/plat-omap/i2c.c
===================================================================
--- kernel-omap4-base.orig/arch/arm/plat-omap/i2c.c
+++ kernel-omap4-base/arch/arm/plat-omap/i2c.c
@@ -53,9 +53,16 @@ static struct resource i2c_resources[][2
 #if	defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 	{ I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, INT_24XX_I2C2_IRQ) },
 #endif
+#if     defined(CONFIG_ARCH_OMAP4)
+	{ I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, INT_44XX_I2C2_IRQ) },
+#endif
+
 #if	defined(CONFIG_ARCH_OMAP34XX)
 	{ I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, INT_34XX_I2C3_IRQ) },
 #endif
+#if     defined(CONFIG_ARCH_OMAP4)
+	{ I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, INT_44XX_I2C3_IRQ) },
+#endif
 };

 #define I2C_DEV_BUILDER(bus_id, res, data)		\
@@ -72,10 +79,11 @@ static struct resource i2c_resources[][2
 static u32 i2c_rate[ARRAY_SIZE(i2c_resources)];
 static struct platform_device omap_i2c_devices[] = {
 	I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]),
-#if	defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+#if	defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+	defined(CONFIG_ARCH_OMAP4)
 	I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]),
 #endif
-#if	defined(CONFIG_ARCH_OMAP34XX)
+#if	defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
 	I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]),
 #endif
 };
@@ -88,7 +96,7 @@ static const int omap24xx_pins[][2] = {
 #else
 static const int omap24xx_pins[][2] = {};
 #endif
-#if defined(CONFIG_ARCH_OMAP34XX)
+#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4)
 static const int omap34xx_pins[][2] = {
 	{ K21_34XX_I2C1_SCL, J21_34XX_I2C1_SDA},
 	{ AF15_34XX_I2C2_SCL, AE15_34XX_I2C2_SDA},
@@ -110,7 +118,7 @@ static void __init omap_i2c_mux_pins(int
 	} else if (cpu_is_omap24xx()) {
 		scl = omap24xx_pins[bus][0];
 		sda = omap24xx_pins[bus][1];
-	} else if (cpu_is_omap34xx()) {
+	} else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		scl = omap34xx_pins[bus][0];
 		sda = omap34xx_pins[bus][1];
 	} else {
@@ -129,7 +137,7 @@ static int __init omap_i2c_nr_ports(void
 		ports = 1;
 	else if (cpu_is_omap24xx())
 		ports = 2;
-	else if (cpu_is_omap34xx())
+	else if (cpu_is_omap34xx() || cpu_is_omap44xx())
 		ports = 3;

 	return ports;
@@ -151,6 +159,10 @@ static int __init omap_i2c_add_bus(int b
 			base = OMAP2_I2C_BASE1;
 			irq = INT_24XX_I2C1_IRQ;
 		}
+		if (cpu_is_omap44xx()) {
+			base = OMAP2_I2C_BASE1;
+			irq = INT_44XX_I2C1_IRQ;
+		}
 		res[0].start = base;
 		res[0].end = base + OMAP_I2C_SIZE;
 		res[1].start = irq;
Index: kernel-omap4-base/drivers/i2c/busses/i2c-omap.c
===================================================================
--- kernel-omap4-base.orig/drivers/i2c/busses/i2c-omap.c
+++ kernel-omap4-base/drivers/i2c/busses/i2c-omap.c
@@ -45,28 +45,34 @@
 #define OMAP_I2C_REV_ON_2430		0x36
 #define OMAP_I2C_REV_ON_3430		0x3C

+#define OMAP_I2C_REV_ON_4430		0x40
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))

-#define OMAP_I2C_REV_REG		0x00
-#define OMAP_I2C_IE_REG			0x04
-#define OMAP_I2C_STAT_REG		0x08
-#define OMAP_I2C_IV_REG			0x0c
-/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
-#define OMAP_I2C_WE_REG			0x0c
-#define OMAP_I2C_SYSS_REG		0x10
-#define OMAP_I2C_BUF_REG		0x14
-#define OMAP_I2C_CNT_REG		0x18
-#define OMAP_I2C_DATA_REG		0x1c
-#define OMAP_I2C_SYSC_REG		0x20
-#define OMAP_I2C_CON_REG		0x24
-#define OMAP_I2C_OA_REG			0x28
-#define OMAP_I2C_SA_REG			0x2c
-#define OMAP_I2C_PSC_REG		0x30
-#define OMAP_I2C_SCLL_REG		0x34
-#define OMAP_I2C_SCLH_REG		0x38
-#define OMAP_I2C_SYSTEST_REG		0x3c
-#define OMAP_I2C_BUFSTAT_REG		0x40
+enum {
+	OMAP_I2C_REV_REG = 0,
+	OMAP_I2C_IE_REG,
+	OMAP_I2C_STAT_REG,
+	OMAP_I2C_IV_REG,
+	OMAP_I2C_WE_REG,
+	OMAP_I2C_SYSS_REG,
+	OMAP_I2C_BUF_REG,
+	OMAP_I2C_CNT_REG,
+	OMAP_I2C_DATA_REG,
+	OMAP_I2C_SYSC_REG,
+	OMAP_I2C_CON_REG,
+	OMAP_I2C_OA_REG,
+	OMAP_I2C_SA_REG,
+	OMAP_I2C_PSC_REG,
+	OMAP_I2C_SCLL_REG,
+	OMAP_I2C_SCLH_REG,
+	OMAP_I2C_SYSTEST_REG,
+	OMAP_I2C_BUFSTAT_REG,
+	OMAP_I2C_REVNB_LO,
+	OMAP_I2C_IRQSTATUS_RAW,
+	OMAP_I2C_IRQENABLE_SET,
+	OMAP_I2C_IRQENABLE_CLR,
+};

 /* I2C Interrupt Enable Register (OMAP_I2C_IE): */
 #define OMAP_I2C_IE_XDR		(1 << 14)	/* TX Buffer drain int enable */
@@ -156,6 +162,12 @@
 #define SYSC_IDLEMODE_SMART		0x2
 #define SYSC_CLOCKACTIVITY_FCLK		0x2

+#define maxvalue(x, y)	(x > y ? x : y)
+
+struct reg_type {
+	u32 reg;
+	u32 offset;
+};

 struct omap_i2c_dev {
 	struct device		*dev;
@@ -165,6 +177,7 @@ struct omap_i2c_dev {
 	struct clk		*fclk;		/* Functional clock */
 	struct completion	cmd_complete;
 	struct resource		*ioarea;
+	struct reg_type		*regs;
 	u32			speed;		/* Speed of bus in Khz */
 	u16			cmd_err;
 	u8			*buf;
@@ -180,15 +193,61 @@ struct omap_i2c_dev {
 	u16			iestate;	/* Saved interrupt register */
 };

+static struct  __initdata reg_type reg_map[] = {
+	{OMAP_I2C_REV_REG, 0x00},
+	{OMAP_I2C_IE_REG, 0x04},
+	{OMAP_I2C_STAT_REG, 0x08},
+	{OMAP_I2C_IV_REG, 0x0c},
+	{OMAP_I2C_WE_REG, 0x0c},
+	{OMAP_I2C_SYSS_REG, 0x10},
+	{OMAP_I2C_BUF_REG, 0x14},
+	{OMAP_I2C_CNT_REG, 0x18},
+	{OMAP_I2C_DATA_REG, 0x1c},
+	{OMAP_I2C_SYSC_REG, 0x20},
+	{OMAP_I2C_CON_REG, 0x24},
+	{OMAP_I2C_OA_REG, 0x28},
+	{OMAP_I2C_SA_REG, 0x2c},
+	{OMAP_I2C_PSC_REG, 0x30},
+	{OMAP_I2C_SCLL_REG, 0x34},
+	{OMAP_I2C_SCLH_REG, 0x38},
+	{OMAP_I2C_SYSTEST_REG, 0x3C},
+	{OMAP_I2C_BUFSTAT_REG, 0x40},
+};
+
+static struct  __initdata reg_type omap4_reg_map[] = {
+	{OMAP_I2C_REV_REG, 0x04},
+	{OMAP_I2C_IE_REG, 0x2c},
+	{OMAP_I2C_STAT_REG, 0x28},
+	{OMAP_I2C_IV_REG, 0x34},
+	{OMAP_I2C_WE_REG, 0x34},
+	{OMAP_I2C_SYSS_REG, 0x90},
+	{OMAP_I2C_BUF_REG, 0x94},
+	{OMAP_I2C_CNT_REG, 0x98},
+	{OMAP_I2C_DATA_REG, 0x9c},
+	{OMAP_I2C_SYSC_REG, 0x20},
+	{OMAP_I2C_CON_REG, 0xa4},
+	{OMAP_I2C_OA_REG, 0xa8},
+	{OMAP_I2C_SA_REG, 0xac},
+	{OMAP_I2C_PSC_REG, 0xb0},
+	{OMAP_I2C_SCLL_REG, 0xb4},
+	{OMAP_I2C_SCLH_REG, 0xb8},
+	{OMAP_I2C_SYSTEST_REG, 0xbC},
+	{OMAP_I2C_BUFSTAT_REG, 0xc0},
+	{OMAP_I2C_REVNB_LO, 0x00},
+	{OMAP_I2C_IRQSTATUS_RAW, 0x24},
+	{OMAP_I2C_IRQENABLE_SET, 0x2c},
+	{OMAP_I2C_IRQENABLE_CLR, 0x30},
+};
+
 static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
 				      int reg, u16 val)
 {
-	__raw_writew(val, i2c_dev->base + reg);
+	__raw_writew(val, i2c_dev->base + i2c_dev->regs[reg].offset);
 }

 static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
 {
-	return __raw_readw(i2c_dev->base + reg);
+	return __raw_readw(i2c_dev->base + i2c_dev->regs[reg].offset);
 }

 static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
@@ -242,7 +301,11 @@ static void omap_i2c_idle(struct omap_i2
 	WARN_ON(dev->idle);

 	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_REV_ON_4430)
+		omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
+	else
+		omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+
 	if (dev->rev < OMAP_I2C_REV_2) {
 		iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
 	} else {
@@ -302,6 +365,7 @@ static int omap_i2c_init(struct omap_i2c
 			 * WFI instruction.
 			 * REVISIT: Some wkup sources might not be needed.
 			 */
+		if (dev->rev < OMAP_I2C_REV_ON_4430)
 			omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
 							OMAP_I2C_WE_ALL);

@@ -331,7 +395,7 @@ static int omap_i2c_init(struct omap_i2c
 			psc = fclk_rate / 12000000;
 	}

-	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+	if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {

 		/*
 		 * HSI2C controller internal clk rate should be 19.2 Mhz for
@@ -345,7 +409,11 @@ static int omap_i2c_init(struct omap_i2c
 			internal_clk = 9600;
 		else
 			internal_clk = 4000;
-		fclk_rate = clk_get_rate(dev->fclk) / 1000;
+		/* FIXME: Remove this once clock framework is available*/
+		if (dev->rev >= OMAP_I2C_REV_ON_4430)
+			fclk_rate = 96000;
+		else
+			fclk_rate = clk_get_rate(dev->fclk) / 1000;

 		/* Compute prescaler divisor */
 		psc = fclk_rate / internal_clk;
@@ -702,9 +770,12 @@ omap_i2c_isr(int this_irq, void *dev_id)
 				if (dev->buf_len) {
 					*dev->buf++ = w;
 					dev->buf_len--;
-					/* Data reg from 2430 is 8 bit wide */
+					/* Data reg in 2430, omap3 and
+					 * omap4 is 8 bit wide
+					 */
 					if (!cpu_is_omap2430() &&
-							!cpu_is_omap34xx()) {
+							!cpu_is_omap34xx() &&
+							!cpu_is_omap44xx()) {
 						if (dev->buf_len) {
 							*dev->buf++ = w >> 8;
 							dev->buf_len--;
@@ -741,9 +812,12 @@ omap_i2c_isr(int this_irq, void *dev_id)
 				if (dev->buf_len) {
 					w = *dev->buf++;
 					dev->buf_len--;
-					/* Data reg from  2430 is 8 bit wide */
+					/* Data reg in 2430, omap3 and
+					 * omap4 is 8 bit wide
+					 */
 					if (!cpu_is_omap2430() &&
-							!cpu_is_omap34xx()) {
+							!cpu_is_omap34xx() &&
+							!cpu_is_omap44xx()) {
 						if (dev->buf_len) {
 							w |= *dev->buf++ << 8;
 							dev->buf_len--;
@@ -839,11 +913,25 @@ omap_i2c_probe(struct platform_device *p
 	if ((r = omap_i2c_get_clocks(dev)) != 0)
 		goto err_iounmap;

+	if (dev->regs == NULL) {
+		dev->regs = kmalloc(maxvalue(sizeof(omap4_reg_map),
+				sizeof(reg_map)), GFP_KERNEL);
+		if (dev->regs == NULL) {
+			r = -ENOMEM;
+			goto err_free_mem;
+		}
+	}
+
+	if (cpu_is_omap44xx())
+		memcpy(dev->regs, omap4_reg_map, sizeof(omap4_reg_map));
+	else
+		memcpy(dev->regs, reg_map, sizeof(reg_map));
+
 	omap_i2c_unidle(dev);

 	dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;

-	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+	if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		u16 s;

 		/* Set up the fifo size - Get total size */
@@ -855,8 +943,13 @@ omap_i2c_probe(struct platform_device *p
 		 * size. This is to ensure that we can handle the status on int
 		 * call back latencies.
 		 */
-		dev->fifo_size = (dev->fifo_size / 2);
-		dev->b_hw = 1; /* Enable hardware fixes */
+		if (dev->rev >= OMAP_I2C_REV_ON_4430) {
+			dev->fifo_size = 0;
+			dev->b_hw = 0; /* Enable hardware fixes */
+		} else {
+			dev->fifo_size = (dev->fifo_size / 2);
+			dev->b_hw = 1; /* Enable hardware fixes */
+		}
 	}

 	/* reset ASAP, clearing any IRQs */
@@ -923,6 +1016,7 @@ omap_i2c_remove(struct platform_device *
 	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
 	omap_i2c_put_clocks(dev);
 	iounmap(dev->base);
+	kfree(dev->regs);
 	kfree(dev);
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(mem->start, (mem->end - mem->start) + 1);


--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux