aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristina Warren <cawarren@ti.com>2011-09-27 18:33:02 -0500
committerDan Murphy <dmurphy@ti.com>2011-09-28 08:09:18 -0500
commitab655a90006a467ebb518ddfd98c0d5e598e26ba (patch)
treeb3992b2fc5c62faaba957fe0d48d9123ae5fb6c5
parent4e6366bacf9e248dc605b8f63f14d0830aa75218 (diff)
downloadkernel_samsung_espresso10-ab655a90006a467ebb518ddfd98c0d5e598e26ba.zip
kernel_samsung_espresso10-ab655a90006a467ebb518ddfd98c0d5e598e26ba.tar.gz
kernel_samsung_espresso10-ab655a90006a467ebb518ddfd98c0d5e598e26ba.tar.bz2
OMAP4: I2C: Add hwspinlock support
Adding support for hwspinlock in I2C driver in Blaze and Blaze_Tablet2. Also adding an api omap_i2c_get_hwspinlockid to be used by remote proc to populate the resource table. Change-Id: I5f554ead10806c90442359365dcb8ebff51bf2bf Signed-off-by: Christina Warren <cawarren@ti.com>
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c35
-rw-r--r--arch/arm/mach-omap2/board-44xx-tablet.c34
-rw-r--r--arch/arm/plat-omap/i2c.c41
-rw-r--r--arch/arm/plat-omap/include/plat/i2c.h23
-rw-r--r--drivers/i2c/busses/i2c-omap.c36
-rw-r--r--include/linux/i2c-omap.h4
6 files changed, 173 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 375b595..cf479a0 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -19,6 +19,7 @@
#include <linux/gpio.h>
#include <linux/usb/otg.h>
#include <linux/spi/spi.h>
+#include <linux/hwspinlock.h>
#include <linux/i2c/twl.h>
#include <linux/gpio_keys.h>
#include <linux/regulator/machine.h>
@@ -782,8 +783,42 @@ static void __init blaze_pmic_mux_init(void)
OMAP_WAKEUP_EN);
}
+static void __init omap_i2c_hwspinlock_init(int bus_id, int spinlock_id,
+ struct omap_i2c_bus_board_data *pdata)
+{
+ /* spinlock_id should be -1 for a generic lock request */
+ if (spinlock_id < 0)
+ pdata->handle = hwspin_lock_request();
+ else
+ pdata->handle = hwspin_lock_request_specific(spinlock_id);
+
+ if (pdata->handle != NULL) {
+ pdata->hwspin_lock_timeout = hwspin_lock_timeout;
+ pdata->hwspin_unlock = hwspin_unlock;
+ } else {
+ pr_err("I2C hwspinlock request failed for bus %d\n", \
+ bus_id);
+ }
+}
+
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_1_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_2_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_3_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_4_bus_pdata;
+
static int __init omap4_i2c_init(void)
{
+
+ omap_i2c_hwspinlock_init(1, 0, &sdp4430_i2c_1_bus_pdata);
+ omap_i2c_hwspinlock_init(2, 1, &sdp4430_i2c_2_bus_pdata);
+ omap_i2c_hwspinlock_init(3, 2, &sdp4430_i2c_3_bus_pdata);
+ omap_i2c_hwspinlock_init(4, 3, &sdp4430_i2c_4_bus_pdata);
+
+ omap_register_i2c_bus_board_data(1, &sdp4430_i2c_1_bus_pdata);
+ omap_register_i2c_bus_board_data(2, &sdp4430_i2c_2_bus_pdata);
+ omap_register_i2c_bus_board_data(3, &sdp4430_i2c_3_bus_pdata);
+ omap_register_i2c_bus_board_data(4, &sdp4430_i2c_4_bus_pdata);
+
omap4_pmic_init("twl6030", &sdp4430_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
diff --git a/arch/arm/mach-omap2/board-44xx-tablet.c b/arch/arm/mach-omap2/board-44xx-tablet.c
index d9886e5..91b5f8d 100644
--- a/arch/arm/mach-omap2/board-44xx-tablet.c
+++ b/arch/arm/mach-omap2/board-44xx-tablet.c
@@ -21,6 +21,7 @@
#include <linux/reboot.h>
#include <linux/usb/otg.h>
#include <linux/spi/spi.h>
+#include <linux/hwspinlock.h>
#include <linux/i2c/twl.h>
#include <linux/twl6040-vib.h>
#include <linux/regulator/machine.h>
@@ -523,8 +524,41 @@ static void __init tablet_pmic_mux_init(void)
OMAP_WAKEUP_EN);
}
+static void __init omap_i2c_hwspinlock_init(int bus_id, int spinlock_id,
+ struct omap_i2c_bus_board_data *pdata)
+{
+ /* spinlock_id should be -1 for a generic lock request */
+ if (spinlock_id < 0)
+ pdata->handle = hwspin_lock_request();
+ else
+ pdata->handle = hwspin_lock_request_specific(spinlock_id);
+
+ if (pdata->handle != NULL) {
+ pdata->hwspin_lock_timeout = hwspin_lock_timeout;
+ pdata->hwspin_unlock = hwspin_unlock;
+ } else {
+ pr_err("I2C hwspinlock request failed for bus %d\n", \
+ bus_id);
+ }
+}
+
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_1_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_2_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_3_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata sdp4430_i2c_4_bus_pdata;
+
static int __init omap4_i2c_init(void)
{
+ omap_i2c_hwspinlock_init(1, 0, &sdp4430_i2c_1_bus_pdata);
+ omap_i2c_hwspinlock_init(2, 1, &sdp4430_i2c_2_bus_pdata);
+ omap_i2c_hwspinlock_init(3, 2, &sdp4430_i2c_3_bus_pdata);
+ omap_i2c_hwspinlock_init(4, 3, &sdp4430_i2c_4_bus_pdata);
+
+ omap_register_i2c_bus_board_data(1, &sdp4430_i2c_1_bus_pdata);
+ omap_register_i2c_bus_board_data(2, &sdp4430_i2c_2_bus_pdata);
+ omap_register_i2c_bus_board_data(3, &sdp4430_i2c_3_bus_pdata);
+ omap_register_i2c_bus_board_data(4, &sdp4430_i2c_4_bus_pdata);
+
omap4_pmic_init("twl6030", &tablet_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, tablet_i2c_3_boardinfo,
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index f8dc82f..0e8c407 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -250,3 +250,44 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
return omap_i2c_add_bus(bus_id);
}
+
+/**
+ * omap_register_i2c_bus_board_data - register hwspinlock data
+ * @bus_id: bus id counting from number 1
+ * @pdata: pointer to the I2C bus board data
+ */
+void omap_register_i2c_bus_board_data(int bus_id,
+ struct omap_i2c_bus_board_data *pdata)
+{
+ BUG_ON(bus_id < 1 || bus_id > omap_i2c_nr_ports());
+
+ if ((pdata != NULL) && (pdata->handle != NULL)) {
+ i2c_pdata[bus_id - 1].handle = pdata->handle;
+ i2c_pdata[bus_id - 1].hwspin_lock_timeout =
+ pdata->hwspin_lock_timeout;
+ i2c_pdata[bus_id - 1].hwspin_unlock = pdata->hwspin_unlock;
+ }
+}
+
+/**
+ * omap_i2c_get_hwspinlockid - Get HWSPINLOCK ID for I2C device
+ * @dev: I2C device
+ *
+ * returns the hwspinlock id or -1 if does not exist
+ */
+int omap_i2c_get_hwspinlockid(struct device *dev)
+{
+ struct omap_i2c_bus_platform_data *pdata;
+
+ pdata = dev_get_platdata(dev);
+ if (!pdata) {
+ dev_err(dev, "%s: platform data is missing\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pdata->handle != NULL)
+ return hwspin_lock_get_id(pdata->handle);
+ else
+ return -1;
+}
+EXPORT_SYMBOL_GPL(omap_i2c_get_hwspinlockid);
diff --git a/arch/arm/plat-omap/include/plat/i2c.h b/arch/arm/plat-omap/include/plat/i2c.h
index 878d632..2f7164b 100644
--- a/arch/arm/plat-omap/include/plat/i2c.h
+++ b/arch/arm/plat-omap/include/plat/i2c.h
@@ -22,6 +22,29 @@
#define __ASM__ARCH_OMAP_I2C_H
#include <linux/i2c.h>
+#include <linux/hwspinlock.h>
+
+struct omap_i2c_bus_board_data {
+ struct hwspinlock *handle;
+ int (*hwspin_lock_timeout)(struct hwspinlock *hwlock, unsigned int to);
+ void (*hwspin_unlock)(struct hwspinlock *hwlock);
+};
+
+/**
+ * omap_register_i2c_bus_board_data - register hwspinlock data
+ * @bus_id: bus id counting from number 1
+ * @pdata: pointer to the I2C bus board data
+ */
+void omap_register_i2c_bus_board_data(int bus_id,
+ struct omap_i2c_bus_board_data *pdata);
+
+/**
+ * omap_i2c_get_hwspinlockid - Get HWSPINLOCK ID for I2C device
+ * @dev: I2C device
+ *
+ * returns the hwspinlock id or -1 if does not exist
+ */
+int omap_i2c_get_hwspinlockid(struct device *dev);
#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 85abf9a..eec68f9 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -38,6 +38,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/hwspinlock.h>
#include <linux/i2c-omap.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos_params.h>
@@ -266,6 +267,31 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
(i2c_dev->regs[reg] << i2c_dev->reg_shift));
}
+static int omap_i2c_hwspinlock_lock(struct omap_i2c_dev *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev->dev);
+ struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+ int ret = 0;
+
+ if (pdata->hwspin_lock_timeout) {
+ ret = pdata->hwspin_lock_timeout(pdata->handle, 100);
+ if (ret != 0)
+ dev_err(&pdev->dev, "%s: TIMEDOUT: Failed to acquire "
+ "hwspinlock\n", __func__);
+ return ret;
+ } else
+ return -EINVAL;
+}
+
+static void omap_i2c_hwspinlock_unlock(struct omap_i2c_dev *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev->dev);
+ struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+
+ if (pdata->hwspin_unlock)
+ pdata->hwspin_unlock(pdata->handle);
+}
+
static void omap_i2c_unidle(struct omap_i2c_dev *dev)
{
struct platform_device *pdev;
@@ -631,6 +657,15 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
int i;
int r;
+ if (dev == NULL)
+ return -EINVAL;
+
+ r = omap_i2c_hwspinlock_lock(dev);
+ /* To-Do: if we are unable to acquire the lock, we must
+ try to recover somehow */
+ if (r != 0)
+ return r;
+
omap_i2c_unidle(dev);
r = omap_i2c_wait_for_bb(dev);
@@ -661,6 +696,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
omap_i2c_wait_for_bb(dev);
out:
omap_i2c_idle(dev);
+ omap_i2c_hwspinlock_unlock(dev);
return r;
}
diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h
index 3beb390..3ac6cc2 100644
--- a/include/linux/i2c-omap.h
+++ b/include/linux/i2c-omap.h
@@ -9,6 +9,10 @@ struct omap_i2c_bus_platform_data {
int (*device_enable) (struct platform_device *pdev);
int (*device_shutdown) (struct platform_device *pdev);
int (*device_idle) (struct platform_device *pdev);
+ struct hwspinlock *handle;
+ int (*hwspin_lock_timeout)(struct hwspinlock *hwlock,
+ unsigned int to);
+ void (*hwspin_unlock)(struct hwspinlock *hwlock);
};
#endif