[PATCH 10/10] ARM: OMAP: Move STI support to drivers/misc

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is to allow syncing plat-omap with mainline kernel.

Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx>
---
 arch/arm/plat-omap/Makefile          |    3 -
 arch/arm/plat-omap/sti/Makefile      |    4 -
 arch/arm/plat-omap/sti/sti-console.c |  189 ---------------
 arch/arm/plat-omap/sti/sti-fifo.c    |  117 ---------
 arch/arm/plat-omap/sti/sti-netlink.c |  152 ------------
 arch/arm/plat-omap/sti/sti.c         |  432 ----------------------------------
 drivers/misc/Makefile                |    1 +
 drivers/misc/sti/Makefile            |    4 +
 drivers/misc/sti/sti-console.c       |  189 +++++++++++++++
 drivers/misc/sti/sti-fifo.c          |  117 +++++++++
 drivers/misc/sti/sti-netlink.c       |  152 ++++++++++++
 drivers/misc/sti/sti.c               |  432 ++++++++++++++++++++++++++++++++++
 12 files changed, 895 insertions(+), 897 deletions(-)
 delete mode 100644 arch/arm/plat-omap/sti/Makefile
 delete mode 100644 arch/arm/plat-omap/sti/sti-console.c
 delete mode 100644 arch/arm/plat-omap/sti/sti-fifo.c
 delete mode 100644 arch/arm/plat-omap/sti/sti-netlink.c
 delete mode 100644 arch/arm/plat-omap/sti/sti.c
 create mode 100644 drivers/misc/sti/Makefile
 create mode 100644 drivers/misc/sti/sti-console.c
 create mode 100644 drivers/misc/sti/sti-fifo.c
 create mode 100644 drivers/misc/sti/sti-netlink.c
 create mode 100644 drivers/misc/sti/sti.c

diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index c1ada8f..a3f1f5c 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -14,9 +14,6 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
-# STI support
-obj-$(CONFIG_OMAP_STI) += sti/
-
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
 obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o
diff --git a/arch/arm/plat-omap/sti/Makefile b/arch/arm/plat-omap/sti/Makefile
deleted file mode 100644
index 6ad9bb3..0000000
--- a/arch/arm/plat-omap/sti/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-y += sti.o sti-fifo.o
-
-obj-$(CONFIG_OMAP_STI_CONSOLE)	+= sti-console.o
-obj-$(CONFIG_NET)		+= sti-netlink.o
diff --git a/arch/arm/plat-omap/sti/sti-console.c b/arch/arm/plat-omap/sti/sti-console.c
deleted file mode 100644
index 451a139..0000000
--- a/arch/arm/plat-omap/sti/sti-console.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Console support for OMAP STI/XTI
- *
- * Copyright (C) 2004, 2005, 2006 Nokia Corporation
- * Written by: Paul Mundt <paul.mundt@xxxxxxxxx>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <asm/arch/sti.h>
-#include <asm/arch/board.h>
-
-#define DRV_NAME "sticon"
-
-static struct tty_driver *tty_driver;
-static DEFINE_SPINLOCK(sti_console_lock);
-static unsigned int sti_console_channel = -1;
-static int sti_line_done = -1;
-
-/*
- * Write a string to any channel (including terminating NULL)
- * Returns number of characters written.
- */
-static int sti_channel_puts(const char *string, unsigned int channel, int len)
-{
-	int count = 0;
-
-	/*
-	 * sti_line_done is needed to determine when we have reached the
-	 * end of the line. write() has a tendency to hand us small
-	 * strings which otherwise end up creating newlines.. we need to
-	 * keep the channel open and in append mode until the line has
-	 * been terminated.
-	 */
-	if (sti_line_done != 0) {
-#ifdef __LITTLE_ENDIAN
-		sti_channel_writeb(0xc3, channel);
-#else
-		sti_channel_writeb(0xc0, channel);
-#endif
-		xchg(&sti_line_done, 0);
-	}
-
-	while (*string && count != len) {
-		char c = *string++;
-
-		count++;
-
-		if (c == '\n') {
-			xchg(&sti_line_done, 1);
-			sti_channel_writeb(0, channel);
-			break;
-		} else
-			sti_channel_writeb(c, channel);
-	}
-
-	if (sti_line_done)
-		sti_channel_flush(channel);
-
-	return count;
-}
-
-static int sti_tty_open(struct tty_struct *tty, struct file *filp)
-{
-	return 0;
-}
-
-static int sti_tty_write(struct tty_struct *tty,
-			 const unsigned char *buf, int len)
-{
-	unsigned long flags;
-	int bytes;
-
-	spin_lock_irqsave(&sti_console_lock, flags);
-	bytes = sti_channel_puts(buf, sti_console_channel, len);
-	spin_unlock_irqrestore(&sti_console_lock, flags);
-
-	return bytes;
-}
-
-static int sti_tty_write_room(struct tty_struct *tty)
-{
-	return 0x100000;
-}
-
-static int sti_tty_chars_in_buffer(struct tty_struct *tty)
-{
-	return 0;
-}
-
-static struct tty_operations sti_tty_ops = {
-	.open			= sti_tty_open,
-	.write			= sti_tty_write,
-	.write_room		= sti_tty_write_room,
-	.chars_in_buffer	= sti_tty_chars_in_buffer,
-};
-
-static void sti_console_write(struct console *c, const char *s, unsigned n)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&sti_console_lock, flags);
-	sti_channel_puts(s, sti_console_channel, n);
-	spin_unlock_irqrestore(&sti_console_lock, flags);
-}
-
-static struct tty_driver *sti_console_device(struct console *c, int *index)
-{
-	*index = c->index;
-	return tty_driver;
-}
-
-static int sti_console_setup(struct console *c, char *opts)
-{
-	return 0;
-}
-
-static struct console sti_console = {
-	.name		= DRV_NAME,
-	.write		= sti_console_write,
-	.device		= sti_console_device,
-	.setup		= sti_console_setup,
-	.flags		= CON_PRINTBUFFER | CON_ENABLED,
-	.index		= -1,
-};
-
-static int __init sti_console_init(void)
-{
-	const struct omap_sti_console_config *info;
-
-	info = omap_get_config(OMAP_TAG_STI_CONSOLE,
-			       struct omap_sti_console_config);
-	if (info && info->enable) {
-		add_preferred_console(DRV_NAME, 0, NULL);
-
-		sti_console_channel = info->channel;
-	}
-
-	if (unlikely(sti_console_channel == -1))
-		return -EINVAL;
-
-	register_console(&sti_console);
-
-	return 0;
-}
-__initcall(sti_console_init);
-
-static int __init sti_tty_init(void)
-{
-	struct tty_driver *tty;
-	int ret;
-
-	tty = alloc_tty_driver(1);
-	if (!tty)
-		return -ENOMEM;
-
-	tty->name		= DRV_NAME;
-	tty->driver_name	= DRV_NAME;
-	tty->major		= 0;	/* dynamic major */
-	tty->minor_start	= 0;
-	tty->type		= TTY_DRIVER_TYPE_SYSTEM;
-	tty->subtype		= SYSTEM_TYPE_SYSCONS;
-	tty->init_termios	= tty_std_termios;
-
-	tty_set_operations(tty, &sti_tty_ops);
-
-	ret = tty_register_driver(tty);
-	if (ret) {
-		put_tty_driver(tty);
-		return ret;
-	}
-
-	tty_driver = tty;
-	return 0;
-}
-late_initcall(sti_tty_init);
-
-module_param(sti_console_channel, uint, 0);
-MODULE_PARM_DESC(sti_console_channel, "STI console channel");
-MODULE_AUTHOR("Paul Mundt");
-MODULE_DESCRIPTION("OMAP STI console support");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-fifo.c b/arch/arm/plat-omap/sti/sti-fifo.c
deleted file mode 100644
index 4069d9b..0000000
--- a/arch/arm/plat-omap/sti/sti-fifo.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * STI RX FIFO Support
- *
- * Copyright (C) 2005, 2006 Nokia Corporation
- * Written by:  Paul Mundt <paul.mundt@xxxxxxxxx> and
- *		Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <asm/arch/sti.h>
-
-#define STI_READ_BUFFER_SIZE	1024
-#define sti_buf_pos(pos)	((sti_crb->bufpos + (pos)) % \
-				 STI_READ_BUFFER_SIZE)
-
-static struct sti_cycle_buffer {
-	int bufpos;
-	int datalen;
-	unsigned char *buf;
-} *sti_crb;
-
-/**
- * sti_read_packet - STI read packet (read an entire STI packet)
- * @buf: Buffer to store the packet.
- * @maxsize: Maximum size requested.
- *
- * This reads in a single completed STI packet from the RX FIFOs and
- * places it in @buf for further processing.
- *
- * The return value is < 0 on error, and >= 0 for the number of bytes
- * actually read. As per the STI specification, we require a 0xC1 to
- * indicate the end of the packet, and we don't return the packet until
- * we've read the entire thing in.
- *
- * Due to the size of the FIFOs, it's unrealistic to constantly drain
- * this for 1 or 2 bytes at a time, so we assemble it here and return
- * the whole thing.
- */
-int sti_read_packet(unsigned char *buf, int maxsize)
-{
-	unsigned int pos;
-
-	if (unlikely(!buf))
-		return -EINVAL;
-	if (!sti_crb->datalen)
-		return 0;
-
-	pos = sti_buf_pos(sti_crb->datalen - 1);
-	/* End of packet */
-	if (sti_crb->buf[pos] == 0xC1) {
-		int i;
-
-		for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
-			pos = sti_buf_pos(i);
-			buf[i] = sti_crb->buf[pos];
-		}
-
-		sti_crb->bufpos = sti_buf_pos(i);
-		sti_crb->datalen -= i;
-
-		return i;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(sti_read_packet);
-
-static void sti_fifo_irq(unsigned long arg)
-{
-	/* If there is data read it */
-	while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
-		unsigned int pos = sti_buf_pos(sti_crb->datalen);
-
-		sti_crb->buf[pos] = sti_readl(STI_RX_DR);
-		sti_crb->datalen++;
-	}
-
-	sti_ack_irq(STI_RX_INT);
-}
-
-static int __init sti_fifo_init(void)
-{
-	unsigned int size;
-	int ret;
-
-	size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
-	sti_crb = kmalloc(size, GFP_KERNEL);
-	if (!sti_crb)
-		return -ENOMEM;
-
-	sti_crb->bufpos = sti_crb->datalen = 0;
-	sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
-
-	ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
-	if (ret != 0)
-		kfree(sti_crb);
-
-	return ret;
-}
-
-static void __exit sti_fifo_exit(void)
-{
-	sti_free_irq(STI_RX_INT);
-	kfree(sti_crb);
-}
-
-module_init(sti_fifo_init);
-module_exit(sti_fifo_exit);
-
-MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-netlink.c b/arch/arm/plat-omap/sti/sti-netlink.c
deleted file mode 100644
index ca3533e..0000000
--- a/arch/arm/plat-omap/sti/sti-netlink.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * OMAP STI/XTI communications interface via netlink socket.
- *
- * Copyright (C) 2004, 2005, 2006 Nokia Corporation
- * Written by: Paul Mundt <paul.mundt@xxxxxxxxx>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/netlink.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/mutex.h>
-#include <net/sock.h>
-#include <asm/arch/sti.h>
-
-static struct sock *sti_sock;
-static DEFINE_MUTEX(sti_netlink_mutex);
-
-enum {
-	STI_READ,
-	STI_WRITE,
-};
-
-static int sti_netlink_read(int pid, int seq, void *payload, int size)
-{
-	struct sk_buff *skb;
-	struct nlmsghdr *nlh;
-	int ret, len = NLMSG_SPACE(size);
-	unsigned char *tail;
-
-	skb = alloc_skb(len, GFP_KERNEL);
-	if (!skb)
-		return -ENOMEM;
-
-	tail = skb->tail;
-	nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
-			len - (sizeof(struct nlmsghdr)));
-	nlh->nlmsg_flags = 0;
-	memcpy(NLMSG_DATA(nlh), payload, size);
-	nlh->nlmsg_len = skb->tail - tail;
-
-	ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
-	if (ret > 0)
-		ret = 0;
-
-	return ret;
-
-nlmsg_failure:
-	if (skb)
-		kfree_skb(skb);
-
-	return -EINVAL;
-}
-
-/*
- * We abuse nlmsg_type and nlmsg_flags for our purposes.
- *
- * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
- * channel number is encoded into the upper 8 bits of the nlmsg_flags.
- */
-static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
-{
-	void *data;
-	u8 chan, id;
-	int size, ret = 0, len = 0;
-
-	data	= NLMSG_DATA(nlh);
-	chan	= (nlh->nlmsg_flags >> 8) & 0xff;
-	id	= (nlh->nlmsg_type  >> 8) & 0xff;
-	size	= (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
-
-	switch (nlh->nlmsg_type & 0xff) {
-	case STI_WRITE:
-		sti_channel_write_trace(size, id, data, chan);
-		break;
-	case STI_READ:
-		data = kmalloc(size, GFP_KERNEL);
-		if (!data)
-			return -ENOMEM;
-		memset(data, 0, size);
-
-		len = sti_read_packet(data, size);
-		ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
-				       data, len);
-		kfree(data);
-		break;
-	default:
-		return -ENOTTY;
-	}
-
-	return ret;
-}
-
-static int sti_netlink_receive_skb(struct sk_buff *skb)
-{
-	while (skb->len >= NLMSG_SPACE(0)) {
-		struct nlmsghdr *nlh;
-		u32 rlen;
-		int ret;
-
-		nlh = (struct nlmsghdr *)skb->data;
-		if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
-		    skb->len < nlh->nlmsg_len)
-			break;
-
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-
-		ret = sti_netlink_receive_msg(skb, nlh);
-		if (ret)
-			netlink_ack(skb, nlh, -ret);
-		else if (nlh->nlmsg_flags & NLM_F_ACK)
-			netlink_ack(skb, nlh, 0);
-
-		skb_pull(skb, rlen);
-	}
-
-	return 0;
-}
-
-static void sti_netlink_receive(struct sk_buff *skb)
-{
-	if (!mutex_trylock(&sti_netlink_mutex))
-		return;
-
-	sti_netlink_receive_skb(skb);
-	mutex_unlock(&sti_netlink_mutex);
-}
-
-static int __init sti_netlink_init(void)
-{
-	sti_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0,
-					 sti_netlink_receive, NULL,
-					 THIS_MODULE);
-	if (!sti_sock) {
-		printk(KERN_ERR "STI: Failed to create netlink socket\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-module_init(sti_netlink_init);
-
-MODULE_AUTHOR("Paul Mundt");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("STI netlink-driven communications interface");
diff --git a/arch/arm/plat-omap/sti/sti.c b/arch/arm/plat-omap/sti/sti.c
deleted file mode 100644
index e828860..0000000
--- a/arch/arm/plat-omap/sti/sti.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Support functions for OMAP STI/XTI (Serial Tracing Interface)
- *
- * Copyright (C) 2004, 2005, 2006 Nokia Corporation
- * Written by: Paul Mundt <paul.mundt@xxxxxxxxx>
- *
- * STI initialization code and channel handling
- * from Juha Yrjölä <juha.yrjola@xxxxxxxxx>.
- *
- * XTI initialization
- * from Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx>.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <asm/arch/sti.h>
-#include <asm/byteorder.h>
-
-static struct clk *sti_ck;
-unsigned long sti_base, sti_channel_base;
-static unsigned long sti_kern_mask = STIEn;
-static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
-static DEFINE_SPINLOCK(sti_lock);
-
-static struct sti_irqdesc {
-	irqreturn_t (*func)(unsigned long);
-	unsigned long data;
-} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
-
-void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
-{
-	const u8 *tpntr = data;
-
-	sti_channel_writeb(id, channel);
-
-	if (cpu_is_omap16xx())
-		/* Check u32 boundary */
-		if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
-		     (len >= STI_PERCHANNEL_SIZE)) {
-			const u32 *asrc = data;
-
-			do {
-				sti_channel_writel(cpu_to_be32(*asrc++),
-						   channel);
-				len -= STI_PERCHANNEL_SIZE;
-			} while (len >= STI_PERCHANNEL_SIZE);
-
-			tpntr = (const u8 *)asrc;
-		}
-
-	while (len--)
-		sti_channel_writeb(*tpntr++, channel);
-
-	sti_channel_flush(channel);
-}
-EXPORT_SYMBOL(sti_channel_write_trace);
-
-void sti_enable_irq(unsigned int id)
-{
-	spin_lock_irq(&sti_lock);
-	sti_writel(1 << id, STI_IRQSETEN);
-	spin_unlock_irq(&sti_lock);
-}
-EXPORT_SYMBOL(sti_enable_irq);
-
-void sti_disable_irq(unsigned int id)
-{
-	spin_lock_irq(&sti_lock);
-
-	if (cpu_is_omap16xx())
-		sti_writel(1 << id, STI_IRQCLREN);
-	else if (cpu_is_omap24xx())
-		sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
-	else
-		BUG();
-
-	spin_unlock_irq(&sti_lock);
-}
-EXPORT_SYMBOL(sti_disable_irq);
-
-void sti_ack_irq(unsigned int id)
-{
-	/* Even though the clear state is 0, we have to write 1 to clear */
-	sti_writel(1 << id, STI_IRQSTATUS);
-}
-EXPORT_SYMBOL(sti_ack_irq);
-
-int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
-{
-	struct sti_irqdesc *desc;
-
-	if (unlikely(!handler || irq > STI_NR_IRQS))
-		return -EINVAL;
-
-	desc = sti_irq_desc + irq;
-	if (unlikely(desc->func)) {
-		printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
-				    "%d, consider fixing your code..\n", irq);
-		return -EBUSY;
-	}
-
-	desc->func = handler;
-	desc->data = arg;
-
-	sti_enable_irq(irq);
-	return 0;
-}
-EXPORT_SYMBOL(sti_request_irq);
-
-void sti_free_irq(unsigned int irq)
-{
-	struct sti_irqdesc *desc = sti_irq_desc + irq;
-
-	if (unlikely(irq > STI_NR_IRQS))
-		return;
-
-	sti_disable_irq(irq);
-
-	desc->func = NULL;
-	desc->data = 0;
-}
-EXPORT_SYMBOL(sti_free_irq);
-
-/*
- * This is a bit heavy, so normally we would defer this to a tasklet.
- * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
- * possibly some others), so we just do the irqdesc walking here.
- */
-static irqreturn_t sti_interrupt(int irq, void *dev_id)
-{
-	int ret = IRQ_NONE;
-	u16 status;
-	int i;
-
-	status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
-
-	for (i = 0; status; i++) {
-		struct sti_irqdesc *desc = sti_irq_desc + i;
-		u16 id = 1 << i;
-
-		if (!(status & id))
-			continue;
-
-		if (likely(desc && desc->func))
-			ret |= desc->func(desc->data);
-		if (unlikely(ret == IRQ_NONE)) {
-			printk("STI: spurious interrupt (id %d)\n", id);
-			sti_disable_irq(i);
-			sti_ack_irq(i);
-			ret = IRQ_HANDLED;
-		}
-
-		status &= ~id;
-	}
-
-	return IRQ_RETVAL(ret);
-}
-
-static void omap_sti_reset(void)
-{
-	int i;
-
-	/* Reset STI module */
-	sti_writel(0x02, STI_SYSCONFIG);
-
-	/* Wait a while for the STI module to complete its reset */
-	for (i = 0; i < 10000; i++)
-		if (sti_readl(STI_SYSSTATUS) & 1)
-			break;
-}
-
-static int __init sti_init(void)
-{
-	char buf[64];
-	int i;
-
-	if (cpu_is_omap16xx()) {
-		/* Release ARM Rhea buses peripherals enable */
-		sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
-
-		/* Enable TC1_CK (functional clock) */
-		sti_ck = clk_get(NULL, "tc1_ck");
-	} else if (cpu_is_omap24xx())
-		/* Enable emulation tools clock */
-		sti_ck = clk_get(NULL, "emul_ck");
-
-	if (IS_ERR(sti_ck))
-		return PTR_ERR(sti_ck);
-
-	clk_enable(sti_ck);
-
-	/* Reset STI module */
-	omap_sti_reset();
-
-	/* Enable STI */
-	sti_trace_enable(MPUCmdEn);
-
-	/* Change to custom serial protocol */
-	sti_writel(0x01, STI_SERIAL_CFG);
-
-	/* Set STI clock control register to normal mode */
-	sti_writel(0x00, STI_CLK_CTRL);
-
-	i = sti_readl(STI_REVISION);
-	snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
-	        (i >> 4) & 0x0f, i & 0x0f);
-	printk(KERN_INFO "%s", buf);
-
-	sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
-
-	return 0;
-}
-
-static void sti_exit(void)
-{
-	u32 tmp;
-
-	/*
-	 * This should have already been done by reset, but we switch off
-	 * STI entirely just for added sanity..
-	 */
-	tmp = sti_readl(STI_ER);
-	tmp &= ~STIEn;
-	sti_writel(tmp, STI_ER);
-
-	clk_disable(sti_ck);
-	clk_put(sti_ck);
-}
-
-static void __sti_trace_enable(int event)
-{
-	u32 tmp;
-
-	tmp = sti_readl(STI_ER);
-	tmp |= sti_kern_mask | event;
-	sti_writel(tmp, STI_ER);
-}
-
-int sti_trace_enable(int event)
-{
-	spin_lock_irq(&sti_lock);
-	sti_kern_mask |= event;
-	__sti_trace_enable(event);
-	spin_unlock_irq(&sti_lock);
-
-	return 0;
-}
-EXPORT_SYMBOL(sti_trace_enable);
-
-static void __sti_trace_disable(int event)
-{
-	u32 tmp;
-
-	tmp = sti_readl(STI_DR);
-
-	if (cpu_is_omap16xx()) {
-		tmp |= event;
-		tmp &= ~sti_kern_mask;
-	} else if (cpu_is_omap24xx()) {
-		tmp &= ~event;
-		tmp |= sti_kern_mask;
-	} else
-		BUG();
-
-	sti_writel(tmp, STI_DR);
-}
-
-void sti_trace_disable(int event)
-{
-	spin_lock_irq(&sti_lock);
-	sti_kern_mask &= ~event;
-	__sti_trace_disable(event);
-	spin_unlock_irq(&sti_lock);
-}
-EXPORT_SYMBOL(sti_trace_disable);
-
-static ssize_t
-sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
-}
-
-static ssize_t
-sti_trace_store(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
-{
-	int evt = simple_strtoul(buf, NULL, 0);
-	int mask = ~evt;
-
-	spin_lock_irq(&sti_lock);
-	__sti_trace_disable(mask);
-	__sti_trace_enable(evt);
-	spin_unlock_irq(&sti_lock);
-
-	return count;
-}
-static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
-
-static ssize_t
-sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "0x%04lx\n", sti_irq_mask);
-}
-
-static ssize_t
-sti_imask_store(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
-{
-	spin_lock_irq(&sti_lock);
-	sti_irq_mask = simple_strtoul(buf, NULL, 0);
-	spin_unlock_irq(&sti_lock);
-
-	return count;
-}
-static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
-
-static int __devinit sti_probe(struct platform_device *pdev)
-{
-	struct resource *res, *cres;
-	int ret;
-
-	if (pdev->num_resources != 3) {
-		dev_err(&pdev->dev, "invalid number of resources: %d\n",
-			pdev->num_resources);
-		return -ENODEV;
-	}
-
-	/* STI base */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (unlikely(!res)) {
-		dev_err(&pdev->dev, "invalid mem resource\n");
-		return -ENODEV;
-	}
-
-	/* Channel base */
-	cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (unlikely(!cres)) {
-		dev_err(&pdev->dev, "invalid channel mem resource\n");
-		return -ENODEV;
-	}
-
-	ret = device_create_file(&pdev->dev, &dev_attr_trace);
-	if (unlikely(ret != 0))
-		return ret;
-
-	ret = device_create_file(&pdev->dev, &dev_attr_imask);
-	if (unlikely(ret != 0))
-		goto err;
-
-	sti_base = res->start;
-
-	/*
-	 * OMAP 16xx keeps channels in a relatively sane location,
-	 * whereas 24xx maps them much further out, and so they must be
-	 * remapped.
-	 */
-	if (cpu_is_omap16xx())
-		sti_channel_base = cres->start;
-	else if (cpu_is_omap24xx()) {
-		unsigned int size = cres->end - cres->start;
-
-		sti_channel_base = (unsigned long)ioremap(cres->start, size);
-		if (unlikely(!sti_channel_base)) {
-			ret = -ENODEV;
-			goto err_badremap;
-		}
-	}
-
-	ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
-			  IRQF_DISABLED, "sti", NULL);
-	if (unlikely(ret != 0))
-		goto err_badirq;
-
-	return sti_init();
-
-err_badirq:
-	iounmap((void *)sti_channel_base);
-err_badremap:
-	device_remove_file(&pdev->dev, &dev_attr_imask);
-err:
-	device_remove_file(&pdev->dev, &dev_attr_trace);
-
-	return ret;
-}
-
-static int __devexit sti_remove(struct platform_device *pdev)
-{
-	unsigned int irq = platform_get_irq(pdev, 0);
-
-	if (cpu_is_omap24xx())
-		iounmap((void *)sti_channel_base);
-
-	device_remove_file(&pdev->dev, &dev_attr_trace);
-	device_remove_file(&pdev->dev, &dev_attr_imask);
-	free_irq(irq, NULL);
-	sti_exit();
-
-	return 0;
-}
-
-static struct platform_driver sti_driver = {
-	.probe		= sti_probe,
-	.remove		= __devexit_p(sti_remove),
-	.driver		= {
-		.name	= "sti",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init sti_module_init(void)
-{
-	return platform_driver_register(&sti_driver);
-}
-
-static void __exit sti_module_exit(void)
-{
-	platform_driver_unregister(&sti_driver);
-}
-subsys_initcall(sti_module_init);
-module_exit(sti_module_exit);
-
-MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3b12f5d..d65b43d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -5,6 +5,7 @@ obj- := misc.o	# Dummy rule to force built-in.o to be made
 
 obj-$(CONFIG_IBM_ASM)		+= ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
+obj-$(CONFIG_OMAP_STI)		+= sti/
 obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
 obj-$(CONFIG_ACER_WMI)     += acer-wmi.o
 obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
diff --git a/drivers/misc/sti/Makefile b/drivers/misc/sti/Makefile
new file mode 100644
index 0000000..6ad9bb3
--- /dev/null
+++ b/drivers/misc/sti/Makefile
@@ -0,0 +1,4 @@
+obj-y += sti.o sti-fifo.o
+
+obj-$(CONFIG_OMAP_STI_CONSOLE)	+= sti-console.o
+obj-$(CONFIG_NET)		+= sti-netlink.o
diff --git a/drivers/misc/sti/sti-console.c b/drivers/misc/sti/sti-console.c
new file mode 100644
index 0000000..451a139
--- /dev/null
+++ b/drivers/misc/sti/sti-console.c
@@ -0,0 +1,189 @@
+/*
+ * Console support for OMAP STI/XTI
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@xxxxxxxxx>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <asm/arch/sti.h>
+#include <asm/arch/board.h>
+
+#define DRV_NAME "sticon"
+
+static struct tty_driver *tty_driver;
+static DEFINE_SPINLOCK(sti_console_lock);
+static unsigned int sti_console_channel = -1;
+static int sti_line_done = -1;
+
+/*
+ * Write a string to any channel (including terminating NULL)
+ * Returns number of characters written.
+ */
+static int sti_channel_puts(const char *string, unsigned int channel, int len)
+{
+	int count = 0;
+
+	/*
+	 * sti_line_done is needed to determine when we have reached the
+	 * end of the line. write() has a tendency to hand us small
+	 * strings which otherwise end up creating newlines.. we need to
+	 * keep the channel open and in append mode until the line has
+	 * been terminated.
+	 */
+	if (sti_line_done != 0) {
+#ifdef __LITTLE_ENDIAN
+		sti_channel_writeb(0xc3, channel);
+#else
+		sti_channel_writeb(0xc0, channel);
+#endif
+		xchg(&sti_line_done, 0);
+	}
+
+	while (*string && count != len) {
+		char c = *string++;
+
+		count++;
+
+		if (c == '\n') {
+			xchg(&sti_line_done, 1);
+			sti_channel_writeb(0, channel);
+			break;
+		} else
+			sti_channel_writeb(c, channel);
+	}
+
+	if (sti_line_done)
+		sti_channel_flush(channel);
+
+	return count;
+}
+
+static int sti_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	return 0;
+}
+
+static int sti_tty_write(struct tty_struct *tty,
+			 const unsigned char *buf, int len)
+{
+	unsigned long flags;
+	int bytes;
+
+	spin_lock_irqsave(&sti_console_lock, flags);
+	bytes = sti_channel_puts(buf, sti_console_channel, len);
+	spin_unlock_irqrestore(&sti_console_lock, flags);
+
+	return bytes;
+}
+
+static int sti_tty_write_room(struct tty_struct *tty)
+{
+	return 0x100000;
+}
+
+static int sti_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	return 0;
+}
+
+static struct tty_operations sti_tty_ops = {
+	.open			= sti_tty_open,
+	.write			= sti_tty_write,
+	.write_room		= sti_tty_write_room,
+	.chars_in_buffer	= sti_tty_chars_in_buffer,
+};
+
+static void sti_console_write(struct console *c, const char *s, unsigned n)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sti_console_lock, flags);
+	sti_channel_puts(s, sti_console_channel, n);
+	spin_unlock_irqrestore(&sti_console_lock, flags);
+}
+
+static struct tty_driver *sti_console_device(struct console *c, int *index)
+{
+	*index = c->index;
+	return tty_driver;
+}
+
+static int sti_console_setup(struct console *c, char *opts)
+{
+	return 0;
+}
+
+static struct console sti_console = {
+	.name		= DRV_NAME,
+	.write		= sti_console_write,
+	.device		= sti_console_device,
+	.setup		= sti_console_setup,
+	.flags		= CON_PRINTBUFFER | CON_ENABLED,
+	.index		= -1,
+};
+
+static int __init sti_console_init(void)
+{
+	const struct omap_sti_console_config *info;
+
+	info = omap_get_config(OMAP_TAG_STI_CONSOLE,
+			       struct omap_sti_console_config);
+	if (info && info->enable) {
+		add_preferred_console(DRV_NAME, 0, NULL);
+
+		sti_console_channel = info->channel;
+	}
+
+	if (unlikely(sti_console_channel == -1))
+		return -EINVAL;
+
+	register_console(&sti_console);
+
+	return 0;
+}
+__initcall(sti_console_init);
+
+static int __init sti_tty_init(void)
+{
+	struct tty_driver *tty;
+	int ret;
+
+	tty = alloc_tty_driver(1);
+	if (!tty)
+		return -ENOMEM;
+
+	tty->name		= DRV_NAME;
+	tty->driver_name	= DRV_NAME;
+	tty->major		= 0;	/* dynamic major */
+	tty->minor_start	= 0;
+	tty->type		= TTY_DRIVER_TYPE_SYSTEM;
+	tty->subtype		= SYSTEM_TYPE_SYSCONS;
+	tty->init_termios	= tty_std_termios;
+
+	tty_set_operations(tty, &sti_tty_ops);
+
+	ret = tty_register_driver(tty);
+	if (ret) {
+		put_tty_driver(tty);
+		return ret;
+	}
+
+	tty_driver = tty;
+	return 0;
+}
+late_initcall(sti_tty_init);
+
+module_param(sti_console_channel, uint, 0);
+MODULE_PARM_DESC(sti_console_channel, "STI console channel");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("OMAP STI console support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sti/sti-fifo.c b/drivers/misc/sti/sti-fifo.c
new file mode 100644
index 0000000..4069d9b
--- /dev/null
+++ b/drivers/misc/sti/sti-fifo.c
@@ -0,0 +1,117 @@
+/*
+ * STI RX FIFO Support
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Written by:  Paul Mundt <paul.mundt@xxxxxxxxx> and
+ *		Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/arch/sti.h>
+
+#define STI_READ_BUFFER_SIZE	1024
+#define sti_buf_pos(pos)	((sti_crb->bufpos + (pos)) % \
+				 STI_READ_BUFFER_SIZE)
+
+static struct sti_cycle_buffer {
+	int bufpos;
+	int datalen;
+	unsigned char *buf;
+} *sti_crb;
+
+/**
+ * sti_read_packet - STI read packet (read an entire STI packet)
+ * @buf: Buffer to store the packet.
+ * @maxsize: Maximum size requested.
+ *
+ * This reads in a single completed STI packet from the RX FIFOs and
+ * places it in @buf for further processing.
+ *
+ * The return value is < 0 on error, and >= 0 for the number of bytes
+ * actually read. As per the STI specification, we require a 0xC1 to
+ * indicate the end of the packet, and we don't return the packet until
+ * we've read the entire thing in.
+ *
+ * Due to the size of the FIFOs, it's unrealistic to constantly drain
+ * this for 1 or 2 bytes at a time, so we assemble it here and return
+ * the whole thing.
+ */
+int sti_read_packet(unsigned char *buf, int maxsize)
+{
+	unsigned int pos;
+
+	if (unlikely(!buf))
+		return -EINVAL;
+	if (!sti_crb->datalen)
+		return 0;
+
+	pos = sti_buf_pos(sti_crb->datalen - 1);
+	/* End of packet */
+	if (sti_crb->buf[pos] == 0xC1) {
+		int i;
+
+		for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
+			pos = sti_buf_pos(i);
+			buf[i] = sti_crb->buf[pos];
+		}
+
+		sti_crb->bufpos = sti_buf_pos(i);
+		sti_crb->datalen -= i;
+
+		return i;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(sti_read_packet);
+
+static void sti_fifo_irq(unsigned long arg)
+{
+	/* If there is data read it */
+	while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
+		unsigned int pos = sti_buf_pos(sti_crb->datalen);
+
+		sti_crb->buf[pos] = sti_readl(STI_RX_DR);
+		sti_crb->datalen++;
+	}
+
+	sti_ack_irq(STI_RX_INT);
+}
+
+static int __init sti_fifo_init(void)
+{
+	unsigned int size;
+	int ret;
+
+	size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
+	sti_crb = kmalloc(size, GFP_KERNEL);
+	if (!sti_crb)
+		return -ENOMEM;
+
+	sti_crb->bufpos = sti_crb->datalen = 0;
+	sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
+
+	ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
+	if (ret != 0)
+		kfree(sti_crb);
+
+	return ret;
+}
+
+static void __exit sti_fifo_exit(void)
+{
+	sti_free_irq(STI_RX_INT);
+	kfree(sti_crb);
+}
+
+module_init(sti_fifo_init);
+module_exit(sti_fifo_exit);
+
+MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sti/sti-netlink.c b/drivers/misc/sti/sti-netlink.c
new file mode 100644
index 0000000..ca3533e
--- /dev/null
+++ b/drivers/misc/sti/sti-netlink.c
@@ -0,0 +1,152 @@
+/*
+ * OMAP STI/XTI communications interface via netlink socket.
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@xxxxxxxxx>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/mutex.h>
+#include <net/sock.h>
+#include <asm/arch/sti.h>
+
+static struct sock *sti_sock;
+static DEFINE_MUTEX(sti_netlink_mutex);
+
+enum {
+	STI_READ,
+	STI_WRITE,
+};
+
+static int sti_netlink_read(int pid, int seq, void *payload, int size)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	int ret, len = NLMSG_SPACE(size);
+	unsigned char *tail;
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	tail = skb->tail;
+	nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
+			len - (sizeof(struct nlmsghdr)));
+	nlh->nlmsg_flags = 0;
+	memcpy(NLMSG_DATA(nlh), payload, size);
+	nlh->nlmsg_len = skb->tail - tail;
+
+	ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
+	if (ret > 0)
+		ret = 0;
+
+	return ret;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+
+	return -EINVAL;
+}
+
+/*
+ * We abuse nlmsg_type and nlmsg_flags for our purposes.
+ *
+ * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
+ * channel number is encoded into the upper 8 bits of the nlmsg_flags.
+ */
+static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	void *data;
+	u8 chan, id;
+	int size, ret = 0, len = 0;
+
+	data	= NLMSG_DATA(nlh);
+	chan	= (nlh->nlmsg_flags >> 8) & 0xff;
+	id	= (nlh->nlmsg_type  >> 8) & 0xff;
+	size	= (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
+
+	switch (nlh->nlmsg_type & 0xff) {
+	case STI_WRITE:
+		sti_channel_write_trace(size, id, data, chan);
+		break;
+	case STI_READ:
+		data = kmalloc(size, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		memset(data, 0, size);
+
+		len = sti_read_packet(data, size);
+		ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
+				       data, len);
+		kfree(data);
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	return ret;
+}
+
+static int sti_netlink_receive_skb(struct sk_buff *skb)
+{
+	while (skb->len >= NLMSG_SPACE(0)) {
+		struct nlmsghdr *nlh;
+		u32 rlen;
+		int ret;
+
+		nlh = (struct nlmsghdr *)skb->data;
+		if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
+		    skb->len < nlh->nlmsg_len)
+			break;
+
+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+		if (rlen > skb->len)
+			rlen = skb->len;
+
+		ret = sti_netlink_receive_msg(skb, nlh);
+		if (ret)
+			netlink_ack(skb, nlh, -ret);
+		else if (nlh->nlmsg_flags & NLM_F_ACK)
+			netlink_ack(skb, nlh, 0);
+
+		skb_pull(skb, rlen);
+	}
+
+	return 0;
+}
+
+static void sti_netlink_receive(struct sk_buff *skb)
+{
+	if (!mutex_trylock(&sti_netlink_mutex))
+		return;
+
+	sti_netlink_receive_skb(skb);
+	mutex_unlock(&sti_netlink_mutex);
+}
+
+static int __init sti_netlink_init(void)
+{
+	sti_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0,
+					 sti_netlink_receive, NULL,
+					 THIS_MODULE);
+	if (!sti_sock) {
+		printk(KERN_ERR "STI: Failed to create netlink socket\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+module_init(sti_netlink_init);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STI netlink-driven communications interface");
diff --git a/drivers/misc/sti/sti.c b/drivers/misc/sti/sti.c
new file mode 100644
index 0000000..e828860
--- /dev/null
+++ b/drivers/misc/sti/sti.c
@@ -0,0 +1,432 @@
+/*
+ * Support functions for OMAP STI/XTI (Serial Tracing Interface)
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@xxxxxxxxx>
+ *
+ * STI initialization code and channel handling
+ * from Juha Yrjölä <juha.yrjola@xxxxxxxxx>.
+ *
+ * XTI initialization
+ * from Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx>.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/sti.h>
+#include <asm/byteorder.h>
+
+static struct clk *sti_ck;
+unsigned long sti_base, sti_channel_base;
+static unsigned long sti_kern_mask = STIEn;
+static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
+static DEFINE_SPINLOCK(sti_lock);
+
+static struct sti_irqdesc {
+	irqreturn_t (*func)(unsigned long);
+	unsigned long data;
+} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
+{
+	const u8 *tpntr = data;
+
+	sti_channel_writeb(id, channel);
+
+	if (cpu_is_omap16xx())
+		/* Check u32 boundary */
+		if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
+		     (len >= STI_PERCHANNEL_SIZE)) {
+			const u32 *asrc = data;
+
+			do {
+				sti_channel_writel(cpu_to_be32(*asrc++),
+						   channel);
+				len -= STI_PERCHANNEL_SIZE;
+			} while (len >= STI_PERCHANNEL_SIZE);
+
+			tpntr = (const u8 *)asrc;
+		}
+
+	while (len--)
+		sti_channel_writeb(*tpntr++, channel);
+
+	sti_channel_flush(channel);
+}
+EXPORT_SYMBOL(sti_channel_write_trace);
+
+void sti_enable_irq(unsigned int id)
+{
+	spin_lock_irq(&sti_lock);
+	sti_writel(1 << id, STI_IRQSETEN);
+	spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_enable_irq);
+
+void sti_disable_irq(unsigned int id)
+{
+	spin_lock_irq(&sti_lock);
+
+	if (cpu_is_omap16xx())
+		sti_writel(1 << id, STI_IRQCLREN);
+	else if (cpu_is_omap24xx())
+		sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
+	else
+		BUG();
+
+	spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_disable_irq);
+
+void sti_ack_irq(unsigned int id)
+{
+	/* Even though the clear state is 0, we have to write 1 to clear */
+	sti_writel(1 << id, STI_IRQSTATUS);
+}
+EXPORT_SYMBOL(sti_ack_irq);
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
+{
+	struct sti_irqdesc *desc;
+
+	if (unlikely(!handler || irq > STI_NR_IRQS))
+		return -EINVAL;
+
+	desc = sti_irq_desc + irq;
+	if (unlikely(desc->func)) {
+		printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
+				    "%d, consider fixing your code..\n", irq);
+		return -EBUSY;
+	}
+
+	desc->func = handler;
+	desc->data = arg;
+
+	sti_enable_irq(irq);
+	return 0;
+}
+EXPORT_SYMBOL(sti_request_irq);
+
+void sti_free_irq(unsigned int irq)
+{
+	struct sti_irqdesc *desc = sti_irq_desc + irq;
+
+	if (unlikely(irq > STI_NR_IRQS))
+		return;
+
+	sti_disable_irq(irq);
+
+	desc->func = NULL;
+	desc->data = 0;
+}
+EXPORT_SYMBOL(sti_free_irq);
+
+/*
+ * This is a bit heavy, so normally we would defer this to a tasklet.
+ * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
+ * possibly some others), so we just do the irqdesc walking here.
+ */
+static irqreturn_t sti_interrupt(int irq, void *dev_id)
+{
+	int ret = IRQ_NONE;
+	u16 status;
+	int i;
+
+	status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
+
+	for (i = 0; status; i++) {
+		struct sti_irqdesc *desc = sti_irq_desc + i;
+		u16 id = 1 << i;
+
+		if (!(status & id))
+			continue;
+
+		if (likely(desc && desc->func))
+			ret |= desc->func(desc->data);
+		if (unlikely(ret == IRQ_NONE)) {
+			printk("STI: spurious interrupt (id %d)\n", id);
+			sti_disable_irq(i);
+			sti_ack_irq(i);
+			ret = IRQ_HANDLED;
+		}
+
+		status &= ~id;
+	}
+
+	return IRQ_RETVAL(ret);
+}
+
+static void omap_sti_reset(void)
+{
+	int i;
+
+	/* Reset STI module */
+	sti_writel(0x02, STI_SYSCONFIG);
+
+	/* Wait a while for the STI module to complete its reset */
+	for (i = 0; i < 10000; i++)
+		if (sti_readl(STI_SYSSTATUS) & 1)
+			break;
+}
+
+static int __init sti_init(void)
+{
+	char buf[64];
+	int i;
+
+	if (cpu_is_omap16xx()) {
+		/* Release ARM Rhea buses peripherals enable */
+		sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
+
+		/* Enable TC1_CK (functional clock) */
+		sti_ck = clk_get(NULL, "tc1_ck");
+	} else if (cpu_is_omap24xx())
+		/* Enable emulation tools clock */
+		sti_ck = clk_get(NULL, "emul_ck");
+
+	if (IS_ERR(sti_ck))
+		return PTR_ERR(sti_ck);
+
+	clk_enable(sti_ck);
+
+	/* Reset STI module */
+	omap_sti_reset();
+
+	/* Enable STI */
+	sti_trace_enable(MPUCmdEn);
+
+	/* Change to custom serial protocol */
+	sti_writel(0x01, STI_SERIAL_CFG);
+
+	/* Set STI clock control register to normal mode */
+	sti_writel(0x00, STI_CLK_CTRL);
+
+	i = sti_readl(STI_REVISION);
+	snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
+	        (i >> 4) & 0x0f, i & 0x0f);
+	printk(KERN_INFO "%s", buf);
+
+	sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+	return 0;
+}
+
+static void sti_exit(void)
+{
+	u32 tmp;
+
+	/*
+	 * This should have already been done by reset, but we switch off
+	 * STI entirely just for added sanity..
+	 */
+	tmp = sti_readl(STI_ER);
+	tmp &= ~STIEn;
+	sti_writel(tmp, STI_ER);
+
+	clk_disable(sti_ck);
+	clk_put(sti_ck);
+}
+
+static void __sti_trace_enable(int event)
+{
+	u32 tmp;
+
+	tmp = sti_readl(STI_ER);
+	tmp |= sti_kern_mask | event;
+	sti_writel(tmp, STI_ER);
+}
+
+int sti_trace_enable(int event)
+{
+	spin_lock_irq(&sti_lock);
+	sti_kern_mask |= event;
+	__sti_trace_enable(event);
+	spin_unlock_irq(&sti_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(sti_trace_enable);
+
+static void __sti_trace_disable(int event)
+{
+	u32 tmp;
+
+	tmp = sti_readl(STI_DR);
+
+	if (cpu_is_omap16xx()) {
+		tmp |= event;
+		tmp &= ~sti_kern_mask;
+	} else if (cpu_is_omap24xx()) {
+		tmp &= ~event;
+		tmp |= sti_kern_mask;
+	} else
+		BUG();
+
+	sti_writel(tmp, STI_DR);
+}
+
+void sti_trace_disable(int event)
+{
+	spin_lock_irq(&sti_lock);
+	sti_kern_mask &= ~event;
+	__sti_trace_disable(event);
+	spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_trace_disable);
+
+static ssize_t
+sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
+}
+
+static ssize_t
+sti_trace_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int evt = simple_strtoul(buf, NULL, 0);
+	int mask = ~evt;
+
+	spin_lock_irq(&sti_lock);
+	__sti_trace_disable(mask);
+	__sti_trace_enable(evt);
+	spin_unlock_irq(&sti_lock);
+
+	return count;
+}
+static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
+
+static ssize_t
+sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%04lx\n", sti_irq_mask);
+}
+
+static ssize_t
+sti_imask_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	spin_lock_irq(&sti_lock);
+	sti_irq_mask = simple_strtoul(buf, NULL, 0);
+	spin_unlock_irq(&sti_lock);
+
+	return count;
+}
+static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
+
+static int __devinit sti_probe(struct platform_device *pdev)
+{
+	struct resource *res, *cres;
+	int ret;
+
+	if (pdev->num_resources != 3) {
+		dev_err(&pdev->dev, "invalid number of resources: %d\n",
+			pdev->num_resources);
+		return -ENODEV;
+	}
+
+	/* STI base */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "invalid mem resource\n");
+		return -ENODEV;
+	}
+
+	/* Channel base */
+	cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (unlikely(!cres)) {
+		dev_err(&pdev->dev, "invalid channel mem resource\n");
+		return -ENODEV;
+	}
+
+	ret = device_create_file(&pdev->dev, &dev_attr_trace);
+	if (unlikely(ret != 0))
+		return ret;
+
+	ret = device_create_file(&pdev->dev, &dev_attr_imask);
+	if (unlikely(ret != 0))
+		goto err;
+
+	sti_base = res->start;
+
+	/*
+	 * OMAP 16xx keeps channels in a relatively sane location,
+	 * whereas 24xx maps them much further out, and so they must be
+	 * remapped.
+	 */
+	if (cpu_is_omap16xx())
+		sti_channel_base = cres->start;
+	else if (cpu_is_omap24xx()) {
+		unsigned int size = cres->end - cres->start;
+
+		sti_channel_base = (unsigned long)ioremap(cres->start, size);
+		if (unlikely(!sti_channel_base)) {
+			ret = -ENODEV;
+			goto err_badremap;
+		}
+	}
+
+	ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
+			  IRQF_DISABLED, "sti", NULL);
+	if (unlikely(ret != 0))
+		goto err_badirq;
+
+	return sti_init();
+
+err_badirq:
+	iounmap((void *)sti_channel_base);
+err_badremap:
+	device_remove_file(&pdev->dev, &dev_attr_imask);
+err:
+	device_remove_file(&pdev->dev, &dev_attr_trace);
+
+	return ret;
+}
+
+static int __devexit sti_remove(struct platform_device *pdev)
+{
+	unsigned int irq = platform_get_irq(pdev, 0);
+
+	if (cpu_is_omap24xx())
+		iounmap((void *)sti_channel_base);
+
+	device_remove_file(&pdev->dev, &dev_attr_trace);
+	device_remove_file(&pdev->dev, &dev_attr_imask);
+	free_irq(irq, NULL);
+	sti_exit();
+
+	return 0;
+}
+
+static struct platform_driver sti_driver = {
+	.probe		= sti_probe,
+	.remove		= __devexit_p(sti_remove),
+	.driver		= {
+		.name	= "sti",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sti_module_init(void)
+{
+	return platform_driver_register(&sti_driver);
+}
+
+static void __exit sti_module_exit(void)
+{
+	platform_driver_unregister(&sti_driver);
+}
+subsys_initcall(sti_module_init);
+module_exit(sti_module_exit);
+
+MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
-- 
1.5.3.6

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux