Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 237f8aaf authored by David S. Miller's avatar David S. Miller
Browse files

sparc: Convert uctrl driver to OF driver.

parent a9540d34
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ config OBP_FLASH

config TADPOLE_TS102_UCTRL
	tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
	depends on EXPERIMENTAL && SPARC32
	depends on EXPERIMENTAL
	help
	  Say Y here to directly support the TS102 Microcontroller interface
	  on the Tadpole Sparcbook 3.  This device handles power-management
+120 −96
Original line number Diff line number Diff line
/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $
 * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
 *
 * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
 * Copyright 2008 David S. Miller (davem@davemloft.net)
 */

#include <linux/module.h>
@@ -14,6 +14,8 @@
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/of.h>
#include <linux/of_device.h>

#include <asm/openprom.h>
#include <asm/oplib.h>
@@ -21,7 +23,6 @@
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/sbus.h>

#define UCTRL_MINOR	174

@@ -33,26 +34,26 @@
#endif

struct uctrl_regs {
	volatile u32 uctrl_intr;
	volatile u32 uctrl_data;
	volatile u32 uctrl_stat;
	volatile u32 uctrl_xxx[5];
	u32 uctrl_intr;
	u32 uctrl_data;
	u32 uctrl_stat;
	u32 uctrl_xxx[5];
};

struct ts102_regs {
	volatile u32 card_a_intr;
	volatile u32 card_a_stat;
	volatile u32 card_a_ctrl;
	volatile u32 card_a_xxx;
	volatile u32 card_b_intr;
	volatile u32 card_b_stat;
	volatile u32 card_b_ctrl;
	volatile u32 card_b_xxx;
	volatile u32 uctrl_intr;
	volatile u32 uctrl_data;
	volatile u32 uctrl_stat;
	volatile u32 uctrl_xxx;
	volatile u32 ts102_xxx[4];
	u32 card_a_intr;
	u32 card_a_stat;
	u32 card_a_ctrl;
	u32 card_a_xxx;
	u32 card_b_intr;
	u32 card_b_stat;
	u32 card_b_ctrl;
	u32 card_b_xxx;
	u32 uctrl_intr;
	u32 uctrl_data;
	u32 uctrl_stat;
	u32 uctrl_xxx;
	u32 ts102_xxx[4];
};

/* Bits for uctrl_intr register */
@@ -186,17 +187,15 @@ enum uctrl_opcode {
  POWER_RESTART=0x83,
};

struct uctrl_driver {
	struct uctrl_regs *regs;
static struct uctrl_driver {
	struct uctrl_regs __iomem *regs;
	int irq;
	int pending;
	struct uctrl_status status;
};

static struct uctrl_driver drv;
} *global_driver;

static void uctrl_get_event_status(void);
static void uctrl_get_external_status(void);
static void uctrl_get_event_status(struct uctrl_driver *);
static void uctrl_get_external_status(struct uctrl_driver *);

static int
uctrl_ioctl(struct inode *inode, struct file *file,
@@ -213,16 +212,14 @@ static int
uctrl_open(struct inode *inode, struct file *file)
{
	lock_kernel();
	uctrl_get_event_status();
	uctrl_get_external_status();
	uctrl_get_event_status(global_driver);
	uctrl_get_external_status(global_driver);
	unlock_kernel();
	return 0;
}

static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
{
	struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
	printk("in uctrl_interrupt\n");
	return IRQ_HANDLED;
}

@@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = {
{ \
  unsigned int i; \
  for (i = 0; i < 10000; i++) { \
    if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \
      if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \
      break; \
  } \
  dprintk(("write data 0x%02x\n", value)); \
  driver->regs->uctrl_data = value; \
  sbus_writel(value, &driver->regs->uctrl_data); \
}

/* Wait for something to read, read it, then clear the bit */
@@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = {
  unsigned int i; \
  value = 0; \
  for (i = 0; i < 10000; i++) { \
    if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \
      if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \
      break; \
    udelay(1); \
  } \
  value = driver->regs->uctrl_data; \
  value = sbus_readl(&driver->regs->uctrl_data); \
  dprintk(("read data 0x%02x\n", value)); \
  driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \
  sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \
}

static void uctrl_do_txn(struct uctrl_txn *txn)
static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn)
{
	struct uctrl_driver *driver = &drv;
	int stat, incnt, outcnt, bytecnt, intr;
	u32 byte;

	stat = driver->regs->uctrl_stat;
	intr = driver->regs->uctrl_intr;
	driver->regs->uctrl_stat = stat;
	stat = sbus_readl(&driver->regs->uctrl_stat);
	intr = sbus_readl(&driver->regs->uctrl_intr);
	sbus_writel(stat, &driver->regs->uctrl_stat);

	dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr));

@@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn)
	}
}

static void uctrl_get_event_status(void)
static void uctrl_get_event_status(struct uctrl_driver *driver)
{
	struct uctrl_driver *driver = &drv;
	struct uctrl_txn txn;
	u8 outbits[2];

@@ -317,7 +312,7 @@ static void uctrl_get_event_status(void)
	txn.inbuf = NULL;
	txn.outbuf = outbits;

	uctrl_do_txn(&txn);
	uctrl_do_txn(driver, &txn);

	dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
	driver->status.event_status = 
@@ -325,9 +320,8 @@ static void uctrl_get_event_status(void)
	dprintk(("ev is %x\n", driver->status.event_status));
}

static void uctrl_get_external_status(void)
static void uctrl_get_external_status(struct uctrl_driver *driver)
{
	struct uctrl_driver *driver = &drv;
	struct uctrl_txn txn;
	u8 outbits[2];
	int i, v;
@@ -338,7 +332,7 @@ static void uctrl_get_external_status(void)
	txn.inbuf = NULL;
	txn.outbuf = outbits;

	uctrl_do_txn(&txn);
	uctrl_do_txn(driver, &txn);

	dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
	driver->status.external_status = 
@@ -354,71 +348,101 @@ static void uctrl_get_external_status(void)
	
}

static int __init ts102_uctrl_init(void)
static int __devinit uctrl_probe(struct of_device *op,
				 const struct of_device_id *match)
{
	struct uctrl_driver *driver = &drv;
	int len;
	struct linux_prom_irqs tmp_irq[2];
        unsigned int vaddr[2] = { 0, 0 };
	int tmpnode, uctrlnode = prom_getchild(prom_root_node);
	int err;
	struct uctrl_driver *p;
	int err = -ENOMEM;

	tmpnode = prom_searchsiblings(uctrlnode, "obio");
	p = kzalloc(sizeof(*p), GFP_KERNEL);
	if (!p) {
		printk(KERN_ERR "uctrl: Unable to allocate device struct.\n");
		goto out;
	}

	if (tmpnode)
	  uctrlnode = prom_getchild(tmpnode);
	p->regs = of_ioremap(&op->resource[0], 0,
			     resource_size(&op->resource[0]),
			     "uctrl");
	if (!p->regs) {
		printk(KERN_ERR "uctrl: Unable to map registers.\n");
		goto out_free;
	}

	uctrlnode = prom_searchsiblings(uctrlnode, "uctrl");
	p->irq = op->irqs[0];
	err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
	if (err) {
		printk(KERN_ERR "uctrl: Unable to register irq.\n");
		goto out_iounmap;
	}

	if (!uctrlnode)
		return -ENODEV;
	err = misc_register(&uctrl_dev);
	if (err) {
		printk(KERN_ERR "uctrl: Unable to register misc device.\n");
		goto out_free_irq;
	}

	/* the prom mapped it for us */
	len = prom_getproperty(uctrlnode, "address", (void *) vaddr,
			       sizeof(vaddr));
	driver->regs = (struct uctrl_regs *)vaddr[0];
	sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr);
	printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n",
	       op->node->full_name, p->regs, p->irq);
	uctrl_get_event_status(p);
	uctrl_get_external_status(p);

	len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq,
			       sizeof(tmp_irq));
	dev_set_drvdata(&op->dev, p);
	global_driver = p;

	/* Flush device */
	READUCTLDATA(len);
out:
	return err;

	if(!driver->irq) 
		driver->irq = tmp_irq[0].pri;
out_free_irq:
	free_irq(p->irq, p);

	err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
	if (err) {
		printk("%s: unable to register irq %d\n",
		       __func__, driver->irq);
		return err;
	}
out_iounmap:
	of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));

	if (misc_register(&uctrl_dev)) {
		printk("%s: unable to get misc minor %d\n",
		       __func__, uctrl_dev.minor);
		free_irq(driver->irq, driver);
		return -ENODEV;
out_free:
	kfree(p);
	goto out;
}

	driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK;
	printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq);
	uctrl_get_event_status();
	uctrl_get_external_status();
static int __devexit uctrl_remove(struct of_device *op)
{
	struct uctrl_driver *p = dev_get_drvdata(&op->dev);

	if (p) {
		misc_deregister(&uctrl_dev);
		free_irq(p->irq, p);
		of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
		kfree(p);
	}
	return 0;
}

static void __exit ts102_uctrl_cleanup(void)
static struct of_device_id uctrl_match[] = {
	{
	struct uctrl_driver *driver = &drv;
		.name = "uctrl",
	},
	{},
};
MODULE_DEVICE_TABLE(of, uctrl_match);

	misc_deregister(&uctrl_dev);
	if (driver->irq)
		free_irq(driver->irq, driver);
	if (driver->regs)
		driver->regs = NULL;
static struct of_platform_driver uctrl_driver = {
	.name		= "uctrl",
	.match_table	= uctrl_match,
	.probe		= uctrl_probe,
	.remove		= __devexit_p(uctrl_remove),
};


static int __init uctrl_init(void)
{
	return of_register_driver(&uctrl_driver, &of_bus_type);
}

static void __exit uctrl_exit(void)
{
	of_unregister_driver(&uctrl_driver);
}

module_init(ts102_uctrl_init);
module_exit(ts102_uctrl_cleanup);
module_init(uctrl_init);
module_exit(uctrl_exit);
MODULE_LICENSE("GPL");