diff options
-rwxr-xr-x | arch/arm/mach-omap2/omap_hsi.c | 166 | ||||
-rwxr-xr-x | arch/arm/mach-omap2/pm44xx.c | 12 | ||||
-rwxr-xr-x | drivers/omap_hsi/hsi_driver.c | 20 | ||||
-rwxr-xr-x | drivers/omap_hsi/hsi_driver.h | 2 | ||||
-rw-r--r-- | include/linux/hsi_driver_if.h | 2 |
5 files changed, 197 insertions, 5 deletions
diff --git a/arch/arm/mach-omap2/omap_hsi.c b/arch/arm/mach-omap2/omap_hsi.c index 7389012..9c0510b 100755 --- a/arch/arm/mach-omap2/omap_hsi.c +++ b/arch/arm/mach-omap2/omap_hsi.c @@ -36,11 +36,46 @@ #include "pm.h" #include "dvfs.h" +static int omap_hsi_wakeup_enable(int hsi_port); +static int omap_hsi_wakeup_disable(int hsi_port); #define OMAP_HSI_PLATFORM_DEVICE_DRIVER_NAME "omap_hsi" #define OMAP_HSI_PLATFORM_DEVICE_NAME "omap_hsi.0" #define OMAP_HSI_HWMOD_NAME "hsi" #define OMAP_HSI_HWMOD_CLASSNAME "hsi" +#define OMAP_MUX_MODE_MASK 0x7 + + +/* Hack till correct hwmod-mux api gets used */ +#define CA_WAKE_MUX_REG (0x4a1000C2) +#define OMAP44XX_PADCONF_WAKEUPENABLE0 (1 << 14) +#define OMAP44XX_PADCONF_WAKEUPEVENT0 (1 << 15) + +static int omap_mux_read_signal(const char *muxname) +{ + u16 val = 0; + val = omap_readw(CA_WAKE_MUX_REG); + return val; +} + +static int omap_mux_enable_wakeup(const char *muxname) +{ + u16 val = 0; + val = omap_readw(CA_WAKE_MUX_REG); + val |= OMAP44XX_PADCONF_WAKEUPENABLE0; + omap_writew(val, CA_WAKE_MUX_REG); + return 0; +} + +static int omap_mux_disable_wakeup(const char *muxname) +{ + u16 val = 0; + val = omap_readw(CA_WAKE_MUX_REG); + val &= ~OMAP44XX_PADCONF_WAKEUPENABLE0; + omap_writew(val, CA_WAKE_MUX_REG); + return 0; +} + /* MUX settings for HSI port 1 pins */ static struct omap_device_pad hsi_port1_pads[] __initdata = { { @@ -76,6 +111,8 @@ static struct hsi_port_ctx omap_hsi_port_ctx[] = { .hsr.counters = HSI_COUNTERS_FT_DEFAULT | HSI_COUNTERS_TB_DEFAULT | HSI_COUNTERS_FB_DEFAULT, + .cawake_padconf_name = "usbb1_ulpitll_clk.hsi1_cawake", + .cawake_padconf_hsi_mode = OMAP_MUX_MODE1, }, }; @@ -96,6 +133,10 @@ static struct hsi_platform_data omap_hsi_platform_data = { .device_idle = omap_device_idle, .device_shutdown = omap_device_shutdown, .device_scale = omap_device_scale, + .wakeup_enable = omap_hsi_wakeup_enable, + .wakeup_disable = omap_hsi_wakeup_disable, + .wakeup_is_from_hsi = omap_hsi_is_io_wakeup_from_hsi, + .board_suspend = omap_hsi_prepare_suspend, }; static struct omap_device *hsi_od; @@ -155,6 +196,55 @@ static struct hsi_dev *hsi_get_hsi_controller_data(struct platform_device *pd) } /** +* hsi_get_hsi_port_ctx_data - Returns a pointer on the port context +* +* @hsi_port - port number to obtain context. Range [1, 2] +* +* Return value :* If success: pointer on the HSI port context requested +* * else NULL +*/ +static struct hsi_port_ctx *hsi_get_hsi_port_ctx_data(int hsi_port) +{ + int i; + + for (i = 0; i < omap_hsi_platform_data.num_ports; i++) + if (omap_hsi_platform_data.ctx->pctx[i].port_number == hsi_port) + return &omap_hsi_platform_data.ctx->pctx[i]; + + return NULL; +} + +/** +* omap_hsi_is_io_pad_hsi - Indicates if IO Pad has been muxed for HSI CAWAKE +* +* @hsi_port - port number to check for HSI muxing. Range [1, 2] +* +* Return value :* 0 if CAWAKE Padconf has not been found or CAWAKE not muxed for +* CAWAKE +* * else 1 +*/ +static int omap_hsi_is_io_pad_hsi(int hsi_port) +{ + struct hsi_port_ctx *port_ctx; + u16 val; + + port_ctx = hsi_get_hsi_port_ctx_data(hsi_port); + if (!port_ctx) + return 0; + + /* Check for IO pad */ + val = omap_mux_read_signal(port_ctx->cawake_padconf_name); + if (val == -ENODEV) + return 0; + + /* Continue only if CAWAKE is muxed */ + if ((val & OMAP_MUX_MODE_MASK) != port_ctx->cawake_padconf_hsi_mode) + return 0; + + return 1; +} + +/** * omap_hsi_is_io_wakeup_from_hsi - Indicates an IO wakeup from HSI CAWAKE * * @hsi_port - returns port number which triggered wakeup. Range [1, 2]. @@ -181,6 +271,80 @@ bool omap_hsi_is_io_wakeup_from_hsi(int *hsi_port) } /** +* omap_hsi_wakeup_enable - Enable HSI wakeup feature from RET/OFF mode +* +* @hsi_port - reference to the HSI port onto which enable wakeup feature. +* Range [1, 2] +* +* Return value :* 0 if CAWAKE has been configured to wakeup platform +* * -ENODEV if CAWAKE is not muxed on padconf +*/ +static int omap_hsi_wakeup_enable(int hsi_port) +{ + struct hsi_port_ctx *port_ctx; + int ret = -ENODEV; + + if (omap_hsi_is_io_pad_hsi(hsi_port)) { + port_ctx = hsi_get_hsi_port_ctx_data(hsi_port); + ret = omap_mux_enable_wakeup(port_ctx->cawake_padconf_name); + omap4_trigger_ioctrl(); + } else { + pr_debug("HSI port %d not muxed, failed to enable IO wakeup\n", + hsi_port); + } + + return ret; +} + +/** +* omap_hsi_wakeup_disable - Disable HSI wakeup feature from RET/OFF mode +* +* @hsi_port - reference to the HSI port onto which disable wakeup feature. +* Range [1, 2] +* +* Return value :* 0 if CAWAKE has been configured to not wakeup platform +* * -ENODEV if CAWAKE is not muxed on padconf +*/ +static int omap_hsi_wakeup_disable(int hsi_port) +{ + struct hsi_port_ctx *port_ctx; + int ret = -ENODEV; + + if (omap_hsi_is_io_pad_hsi(hsi_port)) { + port_ctx = hsi_get_hsi_port_ctx_data(hsi_port); + ret = omap_mux_disable_wakeup(port_ctx->cawake_padconf_name); + omap4_trigger_ioctrl(); + } else { + pr_debug("HSI port %d not muxed, failed to disable IO wakeup\n", + hsi_port); + } + + return ret; +} + +/** +* omap_hsi_prepare_suspend - Prepare HSI for suspend mode +* +* @hsi_port - reference to the HSI port. Range [1, 2] +* @dev_may_wakeup - value of sysfs flag indicating device wakeup capability +* +* Return value :* 0 if CAWAKE padconf has been configured properly +* * -ENODEV if CAWAKE is not muxed on padconf. +* +*/ +int omap_hsi_prepare_suspend(int hsi_port, bool dev_may_wakeup) +{ + int ret; + + if (dev_may_wakeup) + ret = omap_hsi_wakeup_enable(hsi_port); + else + ret = omap_hsi_wakeup_disable(hsi_port); + + return ret; +} + +/** * omap_hsi_io_wakeup_check - Check if IO wakeup is from HSI and schedule HSI * processing tasklet * @@ -252,7 +416,7 @@ int omap_hsi_wakeup(int hsi_port) /* the IRQ status register */ disable_irq_nosync(hsi_ctrl->hsi_port[i].irq); - return 0; + return 0; } /* HSI_TODO : This requires some fine tuning & completion of diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 7b73df2..adf6eac 100755 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -1340,6 +1340,7 @@ void omap_pm_clear_dsp_wake_up(void) static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) { u32 irqenable_mpu, irqstatus_mpu; + int hsi_port; irqenable_mpu = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_PRM_IRQENABLE_MPU_OFFSET); @@ -1354,7 +1355,16 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) /* Check if a IO_ST interrupt */ if (irqstatus_mpu & OMAP4430_IO_ST_MASK) { /* Check if HSI caused the IO wakeup */ - omap_hsi_io_wakeup_check(); + + /* HACK: check CAWAKE wakeup event */ + if (cawake_event_flag) { + hsi_port = 1; + cawake_event_flag = 0; + omap_hsi_wakeup(hsi_port); + } else + if (omap_hsi_is_io_wakeup_from_hsi(&hsi_port)) + omap_hsi_wakeup(hsi_port); + omap_uart_resume_idle(); if (!machine_is_tuna()) usbhs_wakeup(); diff --git a/drivers/omap_hsi/hsi_driver.c b/drivers/omap_hsi/hsi_driver.c index 310cf02..4d5758c4 100755 --- a/drivers/omap_hsi/hsi_driver.c +++ b/drivers/omap_hsi/hsi_driver.c @@ -1074,8 +1074,7 @@ static int hsi_pm_resume(struct device *dev) /* Perform (optional) HSI board specific action after platform wakeup */ if (pdata->board_resume) for (i = 0; i < hsi_ctrl->max_p; i++) - pdata->board_resume(hsi_ctrl->hsi_port[i].port_number, - device_may_wakeup(dev)); + pdata->board_resume(hsi_ctrl->hsi_port[i].port_number); return 0; } @@ -1090,8 +1089,10 @@ static int hsi_pm_resume(struct device *dev) */ int hsi_runtime_resume(struct device *dev) { + struct hsi_platform_data *pdata = dev_get_platdata(dev); struct platform_device *pd = to_platform_device(dev); struct hsi_dev *hsi_ctrl = platform_get_drvdata(pd); + unsigned int i; dev_dbg(dev, "%s\n", __func__); @@ -1106,6 +1107,10 @@ int hsi_runtime_resume(struct device *dev) /* Allow data reception */ hsi_hsr_resume(hsi_ctrl); + /* When HSI is ON, no need for IO wakeup mechanism on any HSI port */ + for (i = 0; i < hsi_ctrl->max_p; i++) + pdata->wakeup_disable(hsi_ctrl->hsi_port[i].port_number); + /* HSI device is now fully operational and _must_ be able to */ /* complete I/O operations */ @@ -1122,8 +1127,10 @@ int hsi_runtime_resume(struct device *dev) */ int hsi_runtime_suspend(struct device *dev) { + struct hsi_platform_data *pdata = dev_get_platdata(dev); struct platform_device *pd = to_platform_device(dev); struct hsi_dev *hsi_ctrl = platform_get_drvdata(pd); + int i; dev_dbg(dev, "%s\n", __func__); @@ -1133,6 +1140,15 @@ int hsi_runtime_suspend(struct device *dev) /* Forbid data reception */ hsi_hsr_suspend(hsi_ctrl); + /* HSI is going to IDLE, it needs IO wakeup mechanism enabled */ + if (device_may_wakeup(dev)) + for (i = 0; i < hsi_ctrl->max_p; i++) + pdata->wakeup_enable(hsi_ctrl->hsi_port[i].port_number); + else + for (i = 0; i < hsi_ctrl->max_p; i++) + pdata->wakeup_disable( + hsi_ctrl->hsi_port[i].port_number); + /* HSI is now ready to be put in low power state */ return 0; diff --git a/drivers/omap_hsi/hsi_driver.h b/drivers/omap_hsi/hsi_driver.h index 73f86de..226fe15 100755 --- a/drivers/omap_hsi/hsi_driver.h +++ b/drivers/omap_hsi/hsi_driver.h @@ -231,7 +231,7 @@ struct hsi_platform_data { int (*wakeup_disable) (int hsi_port); bool (*wakeup_is_from_hsi) (int *hsi_port); int (*board_suspend)(int hsi_port, bool dev_may_wakeup); - int (*board_resume)(int hsi_port, bool dev_may_wakeup); + int (*board_resume)(int hsi_port); u8 num_ports; struct hsi_ctrl_ctx *ctx; u8 hsi_gdd_chan_count; diff --git a/include/linux/hsi_driver_if.h b/include/linux/hsi_driver_if.h index 44b242c..c7afe6b 100644 --- a/include/linux/hsi_driver_if.h +++ b/include/linux/hsi_driver_if.h @@ -99,6 +99,8 @@ struct hsi_port_ctx { u32 sys_mpu_enable[2]; struct hst_ctx hst; struct hsr_ctx hsr; + const char *cawake_padconf_name; + int cawake_padconf_hsi_mode; }; /** |