aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xarch/arm/mach-omap2/omap_hsi.c166
-rwxr-xr-xarch/arm/mach-omap2/pm44xx.c12
-rwxr-xr-xdrivers/omap_hsi/hsi_driver.c20
-rwxr-xr-xdrivers/omap_hsi/hsi_driver.h2
-rw-r--r--include/linux/hsi_driver_if.h2
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;
};
/**