]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge omap-drivers
authorTony Lindgren <tony@atomide.com>
Thu, 26 Apr 2007 21:11:16 +0000 (21:11 +0000)
committerTony Lindgren <tony@atomide.com>
Thu, 26 Apr 2007 21:11:16 +0000 (21:11 +0000)
drivers/char/watchdog/omap_wdt.c
drivers/char/watchdog/omap_wdt.h
drivers/i2c/busses/i2c-omap.c

index 84074a697dce54dc2124aba8484f5efc969de594..a080b50fb6c40d0105206290eab81b00b6dd61b3 100644 (file)
 
 #include "omap_wdt.h"
 
+static struct platform_device *omap_wdt_dev;
+
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
-static int omap_wdt_users;
-static struct clk *armwdt_ck = NULL;
-static struct clk *mpu_wdt_ick = NULL;
-static struct clk *mpu_wdt_fck = NULL;
-
 static unsigned int wdt_trgr_pattern = 0x1234;
+struct omap_wdt_dev {
+       void __iomem    *base;          /* physical */
+       struct device   *dev;
+       int             omap_wdt_users;
+       struct clk      *armwdt_ck;
+       struct clk      *mpu_wdt_ick;
+       struct clk      *mpu_wdt_fck;
+       struct resource *mem;
+       struct miscdevice omap_wdt_miscdev;
+};
 
-static void omap_wdt_ping(void)
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
 {
+       void __iomem    *base = wdev->base;
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
        wdt_trgr_pattern = ~wdt_trgr_pattern;
-       omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+       omap_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
        /* reloaded WCRR from WLDR */
 }
 
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base;
+       base = wdev->base;
        /* Sequence to enable the watchdog */
-       omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+       omap_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+       while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
-       omap_writel(0x4444, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+       omap_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+       while ((omap_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
 }
 
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base;
+       base = wdev->base;
        /* sequence required to disable watchdog */
-       omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+       omap_writel(0xAAAA, base + OMAP_WATCHDOG_SPR);  /* TIMER_MODE */
+       while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
-       omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+       omap_writel(0x5555, base + OMAP_WATCHDOG_SPR);  /* TIMER_MODE */
+       while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
 }
 
@@ -105,15 +117,17 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
        timer_margin = new_timeout;
 }
 
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
 {
        u32 pre_margin = GET_WLDR_VAL(timer_margin);
+       void __iomem *base;
+       base = wdev->base;
 
        /* just count up at 32 KHz */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+       while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
-       omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+       omap_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+       while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
 }
 
@@ -123,55 +137,65 @@ static void omap_wdt_set_timeout(void)
 
 static int omap_wdt_open(struct inode *inode, struct file *file)
 {
-       if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+       struct omap_wdt_dev *wdev;
+       void __iomem *base;
+       wdev = platform_get_drvdata(omap_wdt_dev);
+       base = wdev->base;
+       if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
                return -EBUSY;
 
        if (cpu_is_omap16xx())
-               clk_enable(armwdt_ck);  /* Enable the clock */
+               clk_enable(wdev->armwdt_ck);    /* Enable the clock */
 
        if (cpu_is_omap24xx()) {
-               clk_enable(mpu_wdt_ick);    /* Enable the interface clock */
-               clk_enable(mpu_wdt_fck);    /* Enable the functional clock */
+               clk_enable(wdev->mpu_wdt_ick);    /* Enable the interface clock */
+               clk_enable(wdev->mpu_wdt_fck);    /* Enable the functional clock */
        }
 
        /* initialize prescaler */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+       while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
-       omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+       omap_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+       while (omap_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
-       omap_wdt_set_timeout();
-       omap_wdt_enable();
+       file->private_data = (void *) wdev;
+
+       omap_wdt_set_timeout(wdev);
+       omap_wdt_enable(wdev);
+
        return 0;
 }
 
 static int omap_wdt_release(struct inode *inode, struct file *file)
 {
+       struct omap_wdt_dev *wdev;
+       wdev = file->private_data;
        /*
         *      Shut off the timer unless NOWAYOUT is defined.
         */
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
-       omap_wdt_disable();
+
+       omap_wdt_disable(wdev);
 
        if (cpu_is_omap16xx()) {
-               clk_disable(armwdt_ck); /* Disable the clock */
-               clk_put(armwdt_ck);
-               armwdt_ck = NULL;
+               clk_disable(wdev->armwdt_ck);   /* Disable the clock */
+               clk_put(wdev->armwdt_ck);
+               wdev->armwdt_ck = NULL;
        }
 
        if (cpu_is_omap24xx()) {
-               clk_disable(mpu_wdt_ick);       /* Disable the clock */
-               clk_disable(mpu_wdt_fck);       /* Disable the clock */
-               clk_put(mpu_wdt_ick);
-               clk_put(mpu_wdt_fck);
-               mpu_wdt_ick = NULL;
-               mpu_wdt_fck = NULL;
+               clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */
+               clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */
+               clk_put(wdev->mpu_wdt_ick);
+               clk_put(wdev->mpu_wdt_fck);
+               wdev->mpu_wdt_ick = NULL;
+               wdev->mpu_wdt_fck = NULL;
        }
 #else
        printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
 #endif
-       omap_wdt_users = 0;
+       wdev->omap_wdt_users = 0;
        return 0;
 }
 
@@ -179,9 +203,11 @@ static ssize_t
 omap_wdt_write(struct file *file, const char __user *data,
                size_t len, loff_t *ppos)
 {
+       struct omap_wdt_dev *wdev;
+       wdev = file->private_data;
        /* Refresh LOAD_TIME. */
        if (len)
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
        return len;
 }
 
@@ -189,12 +215,14 @@ static int
 omap_wdt_ioctl(struct inode *inode, struct file *file,
        unsigned int cmd, unsigned long arg)
 {
+       struct omap_wdt_dev *wdev;
        int new_margin;
        static struct watchdog_info ident = {
                .identity = "OMAP Watchdog",
                .options = WDIOF_SETTIMEOUT,
                .firmware_version = 0,
        };
+       wdev = file->private_data;
 
        switch (cmd) {
        default:
@@ -212,22 +240,23 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
                        return put_user(omap_prcm_get_reset_sources(),
                                        (int __user *)arg);
        case WDIOC_KEEPALIVE:
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                return 0;
        case WDIOC_SETTIMEOUT:
                if (get_user(new_margin, (int __user *)arg))
                        return -EFAULT;
                omap_wdt_adjust_timeout(new_margin);
 
-               omap_wdt_disable();
-               omap_wdt_set_timeout();
-               omap_wdt_enable();
+               omap_wdt_disable(wdev);
+               omap_wdt_set_timeout(wdev);
+               omap_wdt_enable(wdev);
 
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                /* Fall */
        case WDIOC_GETTIMEOUT:
                return put_user(timer_margin, (int __user *)arg);
        }
+       return 0;
 }
 
 static const struct file_operations omap_wdt_fops = {
@@ -238,96 +267,123 @@ static const struct file_operations omap_wdt_fops = {
        .release = omap_wdt_release,
 };
 
-static struct miscdevice omap_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &omap_wdt_fops
-};
 
 static int __init omap_wdt_probe(struct platform_device *pdev)
 {
        struct resource *res, *mem;
        int ret;
+       struct omap_wdt_dev *wdev;
 
        /* reserve static register mappings */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                return -ENOENT;
 
+       if (omap_wdt_dev)
+               return -EBUSY;
+
        mem = request_mem_region(res->start, res->end - res->start + 1,
                                 pdev->name);
        if (mem == NULL)
                return -EBUSY;
 
-       platform_set_drvdata(pdev, mem);
-
-       omap_wdt_users = 0;
+       wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+       if (!wdev) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       wdev->omap_wdt_users = 0;
+       wdev->mem = mem;
 
        if (cpu_is_omap16xx()) {
-               armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
-               if (IS_ERR(armwdt_ck)) {
-                       ret = PTR_ERR(armwdt_ck);
-                       armwdt_ck = NULL;
+               wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+               if (IS_ERR(wdev->armwdt_ck)) {
+                       ret = PTR_ERR(wdev->armwdt_ck);
+                       wdev->armwdt_ck = NULL;
                        goto fail;
                }
        }
 
        if (cpu_is_omap24xx()) {
-               mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
-               if (IS_ERR(mpu_wdt_ick)) {
-                       ret = PTR_ERR(mpu_wdt_ick);
-                       mpu_wdt_ick = NULL;
+               wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+               if (IS_ERR(wdev->mpu_wdt_ick)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_ick);
+                       wdev->mpu_wdt_ick = NULL;
                        goto fail;
                }
-               mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
-               if (IS_ERR(mpu_wdt_fck)) {
-                       ret = PTR_ERR(mpu_wdt_fck);
-                       mpu_wdt_fck = NULL;
+               wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+               if (IS_ERR(wdev->mpu_wdt_fck)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_fck);
+                       wdev->mpu_wdt_fck = NULL;
                        goto fail;
                }
        }
+       wdev->base = (void __iomem *) (mem->start);
+       platform_set_drvdata(pdev, wdev);
 
-       omap_wdt_disable();
+       omap_wdt_disable(wdev);
        omap_wdt_adjust_timeout(timer_margin);
 
-       omap_wdt_miscdev.parent = &pdev->dev;
-       ret = misc_register(&omap_wdt_miscdev);
+       wdev->omap_wdt_miscdev.parent = &pdev->dev;
+       wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+       wdev->omap_wdt_miscdev.name = "watchdog";
+       wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+
+       ret = misc_register(&(wdev->omap_wdt_miscdev));
        if (ret)
                goto fail;
 
-       pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+       pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+               omap_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+               timer_margin);
 
        /* autogate OCP interface clock */
-       omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+       omap_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+       omap_wdt_dev = pdev;
+
        return 0;
 
 fail:
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
-       release_resource(mem);
+       if (wdev) {
+               platform_set_drvdata(pdev, NULL);
+               if (wdev->armwdt_ck)
+                       clk_put(wdev->armwdt_ck);
+               if (wdev->mpu_wdt_ick)
+                       clk_put(wdev->mpu_wdt_ick);
+               if (wdev->mpu_wdt_fck)
+                       clk_put(wdev->mpu_wdt_fck);
+               kfree(wdev);
+       }
+       if (mem) {
+               release_resource(mem);
+       }
        return ret;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-       omap_wdt_disable();
+       struct omap_wdt_dev *wdev;
+       wdev = platform_get_drvdata(pdev);
+       omap_wdt_disable(wdev);
 }
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-       struct resource *mem = platform_get_drvdata(pdev);
-       misc_deregister(&omap_wdt_miscdev);
-       release_resource(mem);
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
+       struct omap_wdt_dev *wdev;
+       wdev = platform_get_drvdata(pdev);
+
+       misc_deregister(&(wdev->omap_wdt_miscdev));
+       release_resource(wdev->mem);
+       platform_set_drvdata(pdev, NULL);
+       if (wdev->armwdt_ck)
+               clk_put(wdev->armwdt_ck);
+       if (wdev->mpu_wdt_ick)
+               clk_put(wdev->mpu_wdt_ick);
+       if (wdev->mpu_wdt_fck)
+               clk_put(wdev->mpu_wdt_fck);
+       kfree(wdev);
+       omap_wdt_dev = NULL;
        return 0;
 }
 
@@ -341,16 +397,20 @@ static int omap_wdt_remove(struct platform_device *pdev)
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       if (omap_wdt_users)
-               omap_wdt_disable();
+       struct omap_wdt_dev *wdev;
+       wdev = platform_get_drvdata(pdev);
+       if (wdev->omap_wdt_users)
+               omap_wdt_disable(wdev);
        return 0;
 }
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       if (omap_wdt_users) {
-               omap_wdt_enable();
-               omap_wdt_ping();
+       struct omap_wdt_dev *wdev;
+       wdev = platform_get_drvdata(pdev);
+       if (wdev->omap_wdt_users) {
+               omap_wdt_enable(wdev);
+               omap_wdt_ping(wdev);
        }
        return 0;
 }
index 52a532a5114a94795e715d554e5aa57c584917ce..511135db930fdcc3464f8bf194acefeef7ef2fe3 100644 (file)
 #ifndef _OMAP_WATCHDOG_H
 #define _OMAP_WATCHDOG_H
 
-#define OMAP1610_WATCHDOG_BASE         0xfffeb000
-#define OMAP2420_WATCHDOG_BASE         0x48022000      /*WDT Timer 2 */
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WATCHDOG_BASE             OMAP2420_WATCHDOG_BASE
-#else
-#define OMAP_WATCHDOG_BASE             OMAP1610_WATCHDOG_BASE
-#define RM_RSTST_WKUP                  0
-#endif
-
-#define OMAP_WATCHDOG_REV              (OMAP_WATCHDOG_BASE + 0x00)
-#define OMAP_WATCHDOG_SYS_CONFIG       (OMAP_WATCHDOG_BASE + 0x10)
-#define OMAP_WATCHDOG_STATUS           (OMAP_WATCHDOG_BASE + 0x14)
-#define OMAP_WATCHDOG_CNTRL            (OMAP_WATCHDOG_BASE + 0x24)
-#define OMAP_WATCHDOG_CRR              (OMAP_WATCHDOG_BASE + 0x28)
-#define OMAP_WATCHDOG_LDR              (OMAP_WATCHDOG_BASE + 0x2c)
-#define OMAP_WATCHDOG_TGR              (OMAP_WATCHDOG_BASE + 0x30)
-#define OMAP_WATCHDOG_WPS              (OMAP_WATCHDOG_BASE + 0x34)
-#define OMAP_WATCHDOG_SPR              (OMAP_WATCHDOG_BASE + 0x48)
+#define OMAP_WATCHDOG_REV                      (0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG       (0x10)
+#define OMAP_WATCHDOG_STATUS           (0x14)
+#define OMAP_WATCHDOG_CNTRL                    (0x24)
+#define OMAP_WATCHDOG_CRR                      (0x28)
+#define OMAP_WATCHDOG_LDR                      (0x2c)
+#define OMAP_WATCHDOG_TGR                      (0x30)
+#define OMAP_WATCHDOG_WPS                      (0x34)
+#define OMAP_WATCHDOG_SPR                      (0x48)
 
 /* Using the prescaler, the OMAP watchdog could go for many
  * months before firing.  These limits work without scaling,
index 5308d672255e7fb75cbd3c61e6187288ed438771..5f29c25015c2795d97925e612a2dc1f53efcb10f 100644 (file)
@@ -2,13 +2,15 @@
  * TI OMAP I2C master mode driver
  *
  * Copyright (C) 2003 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- *
- * Updated to work with multiple I2C interfaces on 24xx by
- * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
  * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
  *
- * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ *     Tony Lindgren <tony@atomide.com>
+ *     Imre Deak <imre.deak@nokia.com>
+ *     Juha Yrjölä <juha.yrjola@nokia.com>
+ *     Syed Khasim <x0khasim@ti.com>
  *
  * 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
@@ -87,6 +89,7 @@
 /* I2C Configuration Register (OMAP_I2C_CON): */
 #define OMAP_I2C_CON_EN                (1 << 15)       /* I2C module enable */
 #define OMAP_I2C_CON_BE                (1 << 14)       /* Big endian mode */
+#define OMAP_I2C_CON_OPMODE    (1 << 12)       /* High Speed support */
 #define OMAP_I2C_CON_STB       (1 << 11)       /* Start byte mode (master) */
 #define OMAP_I2C_CON_MST       (1 << 10)       /* Master/slave mode */
 #define OMAP_I2C_CON_TRX       (1 << 9)        /* TX/RX mode (master only) */
 #define OMAP_I2C_CON_STP       (1 << 1)        /* Stop cond (master only) */
 #define OMAP_I2C_CON_STT       (1 << 0)        /* Start condition (master) */
 
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL   8
+#define OMAP_I2C_SCLH_HSSCLH   8
+
 /* I2C System Test Register (OMAP_I2C_SYSTEST): */
 #ifdef DEBUG
 #define OMAP_I2C_SYSTEST_ST_EN         (1 << 15)       /* System test enable */
 /* I2C System Configuration Register (OMAP_I2C_SYSC): */
 #define OMAP_I2C_SYSC_SRST             (1 << 1)        /* Soft Reset */
 
-/* REVISIT: Use platform_data instead of module parameters */
-/* Fast Mode = 400 kHz, Standard = 100 kHz */
-static int clock = 100; /* Default: 100 kHz */
-module_param(clock, int, 0);
-MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
-
 struct omap_i2c_dev {
        struct device           *dev;
        void __iomem            *base;          /* virtual */
@@ -127,6 +128,7 @@ struct omap_i2c_dev {
        struct clk              *fclk;          /* Functional clock */
        struct completion       cmd_complete;
        struct resource         *ioarea;
+       u32                     speed;          /* Speed of bus in Khz */
        u16                     cmd_err;
        u8                      *buf;
        size_t                  buf_len;
@@ -154,17 +156,28 @@ static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
                        return -ENODEV;
                }
        }
-
-       dev->fclk = clk_get(dev->dev, "i2c_fck");
-       if (IS_ERR(dev->fclk)) {
-               if (dev->iclk != NULL) {
-                       clk_put(dev->iclk);
-                       dev->iclk = NULL;
+       /* For I2C operations on 2430 we need 96Mhz clock */
+       if (cpu_is_omap2430()) {
+               dev->fclk = clk_get(dev->dev, "i2chs_fck");
+               if (IS_ERR(dev->fclk)) {
+                       if (dev->iclk != NULL) {
+                               clk_put(dev->iclk);
+                               dev->iclk = NULL;
+                       }
+                       dev->fclk = NULL;
+                       return -ENODEV;
+               }
+       } else {
+               dev->fclk = clk_get(dev->dev, "i2c_fck");
+               if (IS_ERR(dev->fclk)) {
+                       if (dev->iclk != NULL) {
+                               clk_put(dev->iclk);
+                               dev->iclk = NULL;
+                       }
+                       dev->fclk = NULL;
+                       return -ENODEV;
                }
-               dev->fclk = NULL;
-               return -ENODEV;
        }
-
        return 0;
 }
 
@@ -194,9 +207,11 @@ static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
 
 static int omap_i2c_init(struct omap_i2c_dev *dev)
 {
-       u16 psc = 0;
+       u16 psc = 0, scll = 0, sclh = 0;
+       u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
        unsigned long fclk_rate = 12000000;
        unsigned long timeout;
+       unsigned long internal_clk = 0;
 
        if (!dev->rev1) {
                omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
@@ -239,27 +254,56 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        psc = fclk_rate / 12000000;
        }
 
+       if (cpu_is_omap2430()) {
+
+               /* HSI2C controller internal clk rate should be 19.2 Mhz */
+               internal_clk = 19200;
+               fclk_rate = clk_get_rate(dev->fclk) / 1000;
+
+               /* Compute prescaler divisor */
+               psc = fclk_rate / internal_clk;
+               psc = psc - 1;
+
+               /* If configured for High Speed */
+               if (dev->speed > 400) {
+                       /* For first phase of HS mode */
+                       fsscll = internal_clk / (400 * 2) - 6;
+                       fssclh = internal_clk / (400 * 2) - 6;
+
+                       /* For second phase of HS mode */
+                       hsscll = fclk_rate / (dev->speed * 2) - 6;
+                       hssclh = fclk_rate / (dev->speed * 2) - 6;
+               } else {
+                       /* To handle F/S modes */
+                       fsscll = internal_clk / (dev->speed * 2) - 6;
+                       fssclh = internal_clk / (dev->speed * 2) - 6;
+               }
+               scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+               sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+       } else {
+               /* Program desired operating rate */
+               fclk_rate /= (psc + 1) * 1000;
+               if (psc > 2)
+                       psc = 2;
+               scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+               sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+       }
+
        /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
        omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
 
-       /* Program desired operating rate */
-       fclk_rate /= (psc + 1) * 1000;
-       if (psc > 2)
-               psc = 2;
-
-       omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
-                          fclk_rate / (clock * 2) - 7 + psc);
-       omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
-                          fclk_rate / (clock * 2) - 7 + psc);
+       /* SCL low and high time values */
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
 
        /* Take the I2C module out of reset: */
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 
        /* Enable interrupts */
        omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
-                          (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
-                           OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
-                           OMAP_I2C_IE_AL));
+                       (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+                       OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+                       OMAP_I2C_IE_AL));
        return 0;
 }
 
@@ -335,6 +379,11 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        dev->cmd_err = 0;
 
        w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+       /* High speed configuration */
+       if (dev->speed > 400)
+               w |= OMAP_I2C_CON_OPMODE;
+
        if (msg->flags & I2C_M_TEN)
                w |= OMAP_I2C_CON_XA;
        if (!(msg->flags & I2C_M_RD))
@@ -581,6 +630,7 @@ omap_i2c_probe(struct platform_device *pdev)
        struct i2c_adapter      *adap;
        struct resource         *mem, *irq, *ioarea;
        int r;
+       u32 *speed = NULL;
 
        /* NOTE: driver uses the static register mapping */
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -601,17 +651,18 @@ omap_i2c_probe(struct platform_device *pdev)
                return -EBUSY;
        }
 
-       if (clock > 200)
-               clock = 400;    /* Fast mode */
-       else
-               clock = 100;    /* Standard mode */
-
        dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
        if (!dev) {
                r = -ENOMEM;
                goto err_release_region;
        }
 
+       if (pdev->dev.platform_data != NULL)
+               speed = (u32 *) pdev->dev.platform_data;
+       else
+               *speed = 100; /* Defualt speed */
+
+       dev->speed = *speed;
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
        dev->base = (void __iomem *) IO_ADDRESS(mem->start);
@@ -637,7 +688,7 @@ omap_i2c_probe(struct platform_device *pdev)
        }
        r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
        dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
-                pdev->id, r >> 4, r & 0xf, clock);
+                pdev->id, r >> 4, r & 0xf, dev->speed);
 
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);