diff options
author | Christina Warren <cawarren@ti.com> | 2011-09-27 18:33:02 -0500 |
---|---|---|
committer | Dan Murphy <dmurphy@ti.com> | 2011-09-28 08:09:18 -0500 |
commit | ab655a90006a467ebb518ddfd98c0d5e598e26ba (patch) | |
tree | b3992b2fc5c62faaba957fe0d48d9123ae5fb6c5 | |
parent | 4e6366bacf9e248dc605b8f63f14d0830aa75218 (diff) | |
download | kernel_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.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-44xx-tablet.c | 34 | ||||
-rw-r--r-- | arch/arm/plat-omap/i2c.c | 41 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/i2c.h | 23 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 36 | ||||
-rw-r--r-- | include/linux/i2c-omap.h | 4 |
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 |