--- /dev/null
+#ifndef __INTEL_MID_HSU_H__
+#define __INTEL_MID_HSU_H__
+
+#define MFLD_HSU_NUM 4
+struct mfld_hsu_info {
+ char *name;
+ int id;
+ int wake_gpio;
+ int rx_gpio;
+ int rx_alt;
+ int tx_gpio;
+ int tx_alt;
+ int cts_gpio;
+ int cts_alt;
+ int rts_gpio;
+ int rts_alt;
+ struct device *dev;
+ irq_handler_t wake_isr;
+};
+
+extern struct mfld_hsu_info *platform_hsu_info;
+extern unsigned char hsu_dma_enable;
+void intel_mid_hsu_suspend(int port);
+void intel_mid_hsu_resume(int port);
+void intel_mid_hsu_switch(int port);
+int intel_mid_hsu_init(int port, struct device *dev, irq_handler_t wake_isr);
+
+
+#endif
+
obj-$(CONFIG_BOARD_CTP) += board-ctp.o
obj-$(CONFIG_BOARD_MRFLD_VP) += board-vp.o
obj-$(CONFIG_BOARD_MRFLD_HVP) += board-hvp.o
+obj-$(CONFIG_SERIAL_MFD_HSU) += mfld-hsu.o
#include <asm/intel_mid_gpadc.h>
#include <asm/intel_mid_pwm.h>
#include <asm/reboot.h>
+#include <asm/intel_mid_hsu.h>
/* the offset for the mapping of global gpio pin to irq */
#define MRST_IRQ_OFFSET 0x100
}
device_initcall(switch_mid_init);
#endif
+
+#ifdef CONFIG_SERIAL_MFD_HSU
+static struct mfld_hsu_info ctp_hsu_info[] = {
+ [0] = {
+ .id = 0,
+ .name = "hsu0",
+ .wake_gpio = 42,
+ .cts_gpio = 96+28,
+ .cts_alt = 1,
+ .rts_gpio = 96+29,
+ .rts_alt = 1,
+ },
+ [1] = {
+ .id = 1,
+ .name = "hsu1",
+ .wake_gpio = 64,
+ .rx_gpio = 64,
+ .rx_alt = 1,
+ .tx_gpio = 65,
+ .tx_alt = 1,
+ .cts_gpio = 68,
+ .cts_alt = 1,
+ .rts_gpio = 66,
+ .rts_alt = 2,
+ },
+ [2] = {
+ .id = 2,
+ .name = "hsu2",
+ .wake_gpio = 67,
+ .rx_gpio = 67,
+ .rx_alt = 1,
+ },
+ [3] = {
+ .id = 1,
+ .name = "hsu3",
+ .wake_gpio = 96+30,
+ .rx_gpio = 96+30,
+ .rx_alt = 1,
+ .tx_gpio = 96+31,
+ .tx_alt = 1,
+ .cts_gpio = 96+33,
+ .cts_alt = 1,
+ .rts_gpio = 96+32,
+ .rts_alt = 2,
+ },
+
+};
+
+static int __init ctp_hsu_init(void)
+{
+ platform_hsu_info = ctp_hsu_info;
+ return 0;
+}
+device_initcall(ctp_hsu_init);
+#endif
--- /dev/null
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/lnw_gpio.h>
+#include <linux/gpio.h>
+#include <asm/setup.h>
+#include <asm/intel_mid_hsu.h>
+
+/* a 3 bits bit-map, from 0 to 7, default 0 */
+unsigned char hsu_dma_enable;
+EXPORT_SYMBOL_GPL(hsu_dma_enable);
+
+int __init setup_hsu_dma_enable_flag(char *p)
+{
+ if (!p)
+ return -EINVAL;
+
+ hsu_dma_enable = (unsigned char)memparse(p, &p);
+ if (hsu_dma_enable & (~0x7))
+ return -EINVAL;
+
+ return 0;
+}
+early_param("hsu_dma", setup_hsu_dma_enable_flag);
+
+static struct mfld_hsu_info default_hsu_info[] = {
+ [0] = {
+ .id = 0,
+ .name = "hsu0",
+ .wake_gpio = 13,
+ .cts_gpio = 96+28,
+ .cts_alt = 1,
+ .rts_gpio = 96+29,
+ .rts_alt = 1,
+ },
+ [1] = {
+ .id = 1,
+ .name = "hsu1",
+ .wake_gpio = 64,
+ .rx_gpio = 64,
+ .rx_alt = 1,
+ .tx_gpio = 65,
+ .tx_alt = 1,
+ .cts_gpio = 68,
+ .cts_alt = 1,
+ .rts_gpio = 66,
+ .rts_alt = 2,
+ },
+ [2] = {
+ .id = 2,
+ .name = "hsu2",
+ },
+ [3] = {
+ .id = 1,
+ .name = "hsu3",
+ .wake_gpio = 96+30,
+ .rx_gpio = 96+30,
+ .rx_alt = 1,
+ .tx_gpio = 96+31,
+ .tx_alt = 1,
+ },
+
+};
+
+struct mfld_hsu_info *platform_hsu_info = default_hsu_info;
+
+static irqreturn_t hsu_wakeup_isr(int irq, void *dev)
+{
+ dev_dbg(dev, "HSU wake up\n");
+ pm_runtime_get(dev);
+ pm_runtime_put(dev);
+ return IRQ_HANDLED;
+}
+
+static void hsu_port_enable(int port)
+{
+ struct mfld_hsu_info *info = platform_hsu_info + port;
+
+ if (info->rx_gpio) {
+ lnw_gpio_set_alt(info->rx_gpio, info->rx_alt);
+ gpio_direction_input(info->rx_gpio);
+ }
+ if (info->tx_gpio) {
+ lnw_gpio_set_alt(info->tx_gpio, info->tx_alt);
+ gpio_direction_output(info->tx_gpio, 0);
+ }
+ if (info->cts_gpio) {
+ lnw_gpio_set_alt(info->cts_gpio, info->cts_alt);
+ gpio_direction_input(info->cts_gpio);
+ }
+ if (info->rts_gpio) {
+ lnw_gpio_set_alt(info->rts_gpio, info->rts_alt);
+ gpio_direction_output(info->rts_gpio, 0);
+ }
+}
+
+static void hsu_port_disable(int port)
+{
+ struct mfld_hsu_info *info = platform_hsu_info + port;
+
+ if (info->rx_gpio) {
+ lnw_gpio_set_alt(info->rx_gpio, LNW_GPIO);
+ gpio_direction_input(info->rx_gpio);
+ }
+ if (info->tx_gpio) {
+ lnw_gpio_set_alt(info->tx_gpio, LNW_GPIO);
+ gpio_direction_input(info->tx_gpio);
+ }
+ if (info->cts_gpio) {
+ lnw_gpio_set_alt(info->cts_gpio, LNW_GPIO);
+ gpio_direction_input(info->cts_gpio);
+ }
+ if (info->rts_gpio) {
+ lnw_gpio_set_alt(info->rts_gpio, LNW_GPIO);
+ gpio_direction_input(info->rts_gpio);
+ }
+}
+
+void intel_mid_hsu_suspend(int port)
+{
+ int ret;
+ struct mfld_hsu_info *info = platform_hsu_info + port;
+
+ if (info->rts_gpio) {
+ lnw_gpio_set_alt(info->rts_gpio, LNW_GPIO);
+ gpio_direction_output(info->rts_gpio, 1);
+ }
+ if (info->wake_gpio) {
+ lnw_gpio_set_alt(info->wake_gpio, LNW_GPIO);
+ gpio_direction_input(info->wake_gpio);
+ udelay(100);
+ ret = request_irq(gpio_to_irq(info->wake_gpio), info->wake_isr,
+ IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
+ info->name, info->dev);
+ if (ret)
+ dev_err(info->dev, "failed to register wakeup irq\n");
+ }
+}
+
+void intel_mid_hsu_resume(int port)
+{
+ struct mfld_hsu_info *info = platform_hsu_info + port;
+
+ if (info->wake_gpio)
+ free_irq(gpio_to_irq(info->wake_gpio), info->dev);
+ hsu_port_enable(port);
+}
+
+void intel_mid_hsu_switch(int port)
+{
+ int i;
+ struct mfld_hsu_info *tmp;
+ struct mfld_hsu_info *info = platform_hsu_info + port;
+
+ for (i = 0; i < MFLD_HSU_NUM; i++) {
+ tmp = platform_hsu_info + i;
+ if (tmp != info && tmp->id == info->id)
+ hsu_port_disable(i);
+ }
+ hsu_port_enable(port);
+}
+
+int intel_mid_hsu_init(int port, struct device *dev, irq_handler_t wake_isr)
+{
+ struct mfld_hsu_info *info;
+
+ if (platform_hsu_info == NULL)
+ return -ENODEV;
+ if (port >= MFLD_HSU_NUM)
+ return -ENODEV;
+ info = platform_hsu_info + port;
+ info->dev = dev;
+ info->wake_isr = wake_isr;
+ if (info->wake_gpio)
+ gpio_request(info->wake_gpio, "hsu");
+ if (info->rx_gpio)
+ gpio_request(info->rx_gpio, "hsu");
+ if (info->tx_gpio)
+ gpio_request(info->tx_gpio, "hsu");
+ if (info->cts_gpio)
+ gpio_request(info->cts_gpio, "hsu");
+ if (info->rts_gpio)
+ gpio_request(info->rts_gpio, "hsu");
+}
+
return 0;
}
-
-/* a 3 bits bit-map, from 0 to 7, default 0 */
-unsigned char hsu_dma_enable;
-EXPORT_SYMBOL_GPL(hsu_dma_enable);
-
-int __init setup_hsu_dma_enable_flag(char *p)
-{
- if (!p)
- return -EINVAL;
-
- hsu_dma_enable = (unsigned char)memparse(p, &p);
- if (hsu_dma_enable & (~0x7))
- return -EINVAL;
-
- return 0;
-}
-early_param("hsu_dma", setup_hsu_dma_enable_flag);
-
-#define HSU0_CTS (13)
-#define HSU0_RTS (96 + 29)
-#define HSU1_RX (64)
-#define HSU1_TX (65)
-#define HSU1_CTS (68)
-#define HSU1_RTS (66)
-#define HSU1_ALT_RX (96 + 30)
-#define HSU1_ALT_TX (96 + 31)
-#define HSU2_RX (67)
-
-/* on = 1: the port1 is muxed (named as port 3) for debug output
- * on = 0: the port1 is for modem fw download.
- */
-void mfld_hsu_port1_switch(int on)
-{
- static int first = 1;
-
- if (unlikely(first)) {
- gpio_request(HSU1_RX, "hsu");
- gpio_request(HSU1_TX, "hsu");
- gpio_request(HSU1_CTS, "hsu");
- gpio_request(HSU1_RTS, "hsu");
- gpio_request(HSU1_ALT_RX, "hsu");
- gpio_request(HSU1_ALT_TX, "hsu");
- first = 0;
- }
- if (on) {
- lnw_gpio_set_alt(HSU1_RX, LNW_GPIO);
- lnw_gpio_set_alt(HSU1_TX, LNW_GPIO);
- lnw_gpio_set_alt(HSU1_CTS, LNW_GPIO);
- lnw_gpio_set_alt(HSU1_RTS, LNW_GPIO);
- gpio_direction_input(HSU1_RX);
- gpio_direction_input(HSU1_TX);
- gpio_direction_input(HSU1_CTS);
- gpio_direction_input(HSU1_RTS);
- gpio_direction_input(HSU1_ALT_RX);
- gpio_direction_output(HSU1_ALT_TX, 0);
- lnw_gpio_set_alt(HSU1_ALT_RX, LNW_ALT_1);
- lnw_gpio_set_alt(HSU1_ALT_TX, LNW_ALT_1);
- } else {
- lnw_gpio_set_alt(HSU1_ALT_RX, LNW_GPIO);
- lnw_gpio_set_alt(HSU1_ALT_TX, LNW_GPIO);
- gpio_direction_input(HSU1_ALT_RX);
- gpio_direction_input(HSU1_ALT_TX);
- gpio_direction_input(HSU1_RX);
- gpio_direction_output(HSU1_TX, 0);
- gpio_direction_input(HSU1_CTS);
- gpio_direction_output(HSU1_RTS, 0);
- lnw_gpio_set_alt(HSU1_RX, LNW_ALT_1);
- lnw_gpio_set_alt(HSU1_TX, LNW_ALT_1);
- lnw_gpio_set_alt(HSU1_CTS, LNW_ALT_1);
- lnw_gpio_set_alt(HSU1_RTS, LNW_ALT_2);
- }
-}
-EXPORT_SYMBOL_GPL(mfld_hsu_port1_switch);
-
-void mfld_hsu_enable_wakeup(int index, struct device *dev, irq_handler_t wakeup)
-{
- int ret;
-
- switch (index) {
- case 0:
- lnw_gpio_set_alt(HSU0_CTS, LNW_GPIO);
- ret = request_irq(gpio_to_irq(HSU0_CTS), wakeup,
- IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
- "hsu0_cts_wakeup", dev);
- if (ret)
- dev_err(dev, "hsu0: failed to register wakeup irq\n");
-
- /* turn off flow control */
- gpio_set_value(HSU0_RTS, 1);
- lnw_gpio_set_alt(HSU0_RTS, LNW_GPIO);
- udelay(100);
- break;
- case 1:
- lnw_gpio_set_alt(HSU1_RX, LNW_GPIO);
- udelay(100);
- ret = request_irq(gpio_to_irq(HSU1_RX), wakeup,
- IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
- "hsu1_rx_wakeup", dev);
- if (ret)
- dev_err(dev, "hsu1: failed to register wakeup irq\n");
- break;
- case 2:
- break;
- case 3:
- lnw_gpio_set_alt(HSU1_ALT_RX, LNW_GPIO);
- udelay(100);
- ret = request_irq(gpio_to_irq(HSU1_ALT_RX), wakeup,
- IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
- "hsu1_rx_wakeup", dev);
- if (ret)
- dev_err(dev, "hsu1: failed to register wakeup irq\n");
- break;
- default:
- dev_err(dev, "hsu: unknow hsu port\n");
- }
-}
-EXPORT_SYMBOL_GPL(mfld_hsu_enable_wakeup);
-
-void mfld_hsu_disable_wakeup(int index, struct device *dev)
-{
- switch (index) {
- case 0:
- free_irq(gpio_to_irq(HSU0_CTS), dev);
- lnw_gpio_set_alt(HSU0_CTS, LNW_ALT_1);
- lnw_gpio_set_alt(HSU0_RTS, LNW_ALT_1);
- break;
- case 1:
- free_irq(gpio_to_irq(HSU1_RX), dev);
- lnw_gpio_set_alt(HSU1_RX, LNW_ALT_1);
- break;
- case 2:
- break;
- case 3:
- free_irq(gpio_to_irq(HSU1_ALT_RX), dev);
- lnw_gpio_set_alt(HSU1_ALT_RX, LNW_ALT_1);
- break;
- default:
- dev_err(dev, "hsu: unknow hsu port\n");
- }
-}
#include <asm/intel-mid.h>
#include <asm/processor.h>
#include <linux/pm_runtime.h>
+#include <asm/intel_mid_hsu.h>
#define MFD_HSU_A0_STEPPING 1
/* wait for mux port to close */
while (up1->running)
msleep(1000);
- mfld_hsu_port1_switch(1);
+ intel_mid_hsu_switch(3);
}
if (up->index == 1) {
struct uart_hsu_port *up3 = serial_hsu_ports[3];
*/
up3->running = 1;
}
- mfld_hsu_port1_switch(0);
+ intel_mid_hsu_switch(1);
}
/* startup function is not under atomic context for sure */
pm_runtime_get_sync(up->dev);
up->running = 0;
if (up->index == 1) {
struct uart_hsu_port *up3 = serial_hsu_ports[3];
- mfld_hsu_port1_switch(1);
+ intel_mid_hsu_switch(3);
if (up3->running) {
mutex_unlock(&hsu_lock);
uart_resume_port(&serial_hsu_reg, &up3->port);
uport->port.irq = pdev->irq;
uport->port.dev = &pdev->dev;
uport->dev = &pdev->dev;
+ intel_mid_hsu_init(index, &pdev->dev, wakeup_irq);
if (index != 3) {
ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
}
#endif
if ( index == 1 ) {
- mfld_hsu_port1_switch(1);
index = 3;
} else
break;
};
#ifdef CONFIG_PM
-void mfld_hsu_enable_wakeup(int index, struct device *dev, irq_handler_t wakeup);
-void mfld_hsu_disable_wakeup(int index, struct device *dev);
-
static bool allow_for_suspend(struct uart_hsu_port *up)
{
struct circ_buf *xmit = &up->port.state->xmit;
if (up->index == 1) {
struct uart_hsu_port *up3 = serial_hsu_ports[3];
if (up3->running) {
- mfld_hsu_enable_wakeup(up3->index, dev, wakeup_irq);
+ intel_mid_hsu_suspend(up3->index);
clear_bit(PM_WAKEUP, &up3->pm_flags);
}
memcpy(up3->reg_shadow + 1, up3->port.membase + 1,
}
memcpy(up->reg_shadow + 1, up->port.membase + 1, HSU_PORT_REG_LENGTH - 1);
if (up->running)
- mfld_hsu_enable_wakeup(up->index, dev, wakeup_irq);
+ intel_mid_hsu_suspend(up->index);
return 0;
}
int dma_rx_on = 0;
if (up->running)
- mfld_hsu_disable_wakeup(up->index, dev);
+ intel_mid_hsu_resume(up->index);
if (up->index == 1) {
struct uart_hsu_port *up3 = serial_hsu_ports[3];
if (up3->running)
- mfld_hsu_disable_wakeup(up3->index, dev);
+ intel_mid_hsu_resume(up3->index);
if (up3->dma_rx_on)
dma_rx_on = 1;
}
if (up->running) {
uart_suspend_port(&serial_hsu_reg, &up->port);
up->running = 1;
- mfld_hsu_enable_wakeup(up->index, dev, wakeup_irq);
+ intel_mid_hsu_suspend(up->index);
}
up->suspended = 1;
}
if (up->suspended && up->running) {
uart_resume_port(&serial_hsu_reg, &up->port);
- mfld_hsu_disable_wakeup(up->index, dev);
+ intel_mid_hsu_resume(up->index);
schedule_work(&up->qwork);
}
up->suspended = 0;