aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sbus/char')
-rw-r--r--drivers/sbus/char/Kconfig2
-rw-r--r--drivers/sbus/char/uctrl.c216
2 files changed, 121 insertions, 97 deletions
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 3fd2bc95b514..1d5d1b4580cd 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -32,7 +32,7 @@ config OBP_FLASH
32 32
33config TADPOLE_TS102_UCTRL 33config TADPOLE_TS102_UCTRL
34 tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)" 34 tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
35 depends on EXPERIMENTAL && SPARC32 35 depends on EXPERIMENTAL
36 help 36 help
37 Say Y here to directly support the TS102 Microcontroller interface 37 Say Y here to directly support the TS102 Microcontroller interface
38 on the Tadpole Sparcbook 3. This device handles power-management 38 on the Tadpole Sparcbook 3. This device handles power-management
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 777637594acd..6cff9777bbc0 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -1,7 +1,7 @@
1/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $ 1/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
2 * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
3 * 2 *
4 * Copyright 1999 Derrick J Brashear (shadow@dementia.org) 3 * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
4 * Copyright 2008 David S. Miller (davem@davemloft.net)
5 */ 5 */
6 6
7#include <linux/module.h> 7#include <linux/module.h>
@@ -14,6 +14,8 @@
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/miscdevice.h> 15#include <linux/miscdevice.h>
16#include <linux/mm.h> 16#include <linux/mm.h>
17#include <linux/of.h>
18#include <linux/of_device.h>
17 19
18#include <asm/openprom.h> 20#include <asm/openprom.h>
19#include <asm/oplib.h> 21#include <asm/oplib.h>
@@ -21,7 +23,6 @@
21#include <asm/irq.h> 23#include <asm/irq.h>
22#include <asm/io.h> 24#include <asm/io.h>
23#include <asm/pgtable.h> 25#include <asm/pgtable.h>
24#include <asm/sbus.h>
25 26
26#define UCTRL_MINOR 174 27#define UCTRL_MINOR 174
27 28
@@ -33,26 +34,26 @@
33#endif 34#endif
34 35
35struct uctrl_regs { 36struct uctrl_regs {
36 volatile u32 uctrl_intr; 37 u32 uctrl_intr;
37 volatile u32 uctrl_data; 38 u32 uctrl_data;
38 volatile u32 uctrl_stat; 39 u32 uctrl_stat;
39 volatile u32 uctrl_xxx[5]; 40 u32 uctrl_xxx[5];
40}; 41};
41 42
42struct ts102_regs { 43struct ts102_regs {
43 volatile u32 card_a_intr; 44 u32 card_a_intr;
44 volatile u32 card_a_stat; 45 u32 card_a_stat;
45 volatile u32 card_a_ctrl; 46 u32 card_a_ctrl;
46 volatile u32 card_a_xxx; 47 u32 card_a_xxx;
47 volatile u32 card_b_intr; 48 u32 card_b_intr;
48 volatile u32 card_b_stat; 49 u32 card_b_stat;
49 volatile u32 card_b_ctrl; 50 u32 card_b_ctrl;
50 volatile u32 card_b_xxx; 51 u32 card_b_xxx;
51 volatile u32 uctrl_intr; 52 u32 uctrl_intr;
52 volatile u32 uctrl_data; 53 u32 uctrl_data;
53 volatile u32 uctrl_stat; 54 u32 uctrl_stat;
54 volatile u32 uctrl_xxx; 55 u32 uctrl_xxx;
55 volatile u32 ts102_xxx[4]; 56 u32 ts102_xxx[4];
56}; 57};
57 58
58/* Bits for uctrl_intr register */ 59/* Bits for uctrl_intr register */
@@ -186,17 +187,15 @@ enum uctrl_opcode {
186 POWER_RESTART=0x83, 187 POWER_RESTART=0x83,
187}; 188};
188 189
189struct uctrl_driver { 190static struct uctrl_driver {
190 struct uctrl_regs *regs; 191 struct uctrl_regs __iomem *regs;
191 int irq; 192 int irq;
192 int pending; 193 int pending;
193 struct uctrl_status status; 194 struct uctrl_status status;
194}; 195} *global_driver;
195
196static struct uctrl_driver drv;
197 196
198static void uctrl_get_event_status(void); 197static void uctrl_get_event_status(struct uctrl_driver *);
199static void uctrl_get_external_status(void); 198static void uctrl_get_external_status(struct uctrl_driver *);
200 199
201static int 200static int
202uctrl_ioctl(struct inode *inode, struct file *file, 201uctrl_ioctl(struct inode *inode, struct file *file,
@@ -213,16 +212,14 @@ static int
213uctrl_open(struct inode *inode, struct file *file) 212uctrl_open(struct inode *inode, struct file *file)
214{ 213{
215 lock_kernel(); 214 lock_kernel();
216 uctrl_get_event_status(); 215 uctrl_get_event_status(global_driver);
217 uctrl_get_external_status(); 216 uctrl_get_external_status(global_driver);
218 unlock_kernel(); 217 unlock_kernel();
219 return 0; 218 return 0;
220} 219}
221 220
222static irqreturn_t uctrl_interrupt(int irq, void *dev_id) 221static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
223{ 222{
224 struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
225 printk("in uctrl_interrupt\n");
226 return IRQ_HANDLED; 223 return IRQ_HANDLED;
227} 224}
228 225
@@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = {
244{ \ 241{ \
245 unsigned int i; \ 242 unsigned int i; \
246 for (i = 0; i < 10000; i++) { \ 243 for (i = 0; i < 10000; i++) { \
247 if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \ 244 if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \
248 break; \ 245 break; \
249 } \ 246 } \
250 dprintk(("write data 0x%02x\n", value)); \ 247 dprintk(("write data 0x%02x\n", value)); \
251 driver->regs->uctrl_data = value; \ 248 sbus_writel(value, &driver->regs->uctrl_data); \
252} 249}
253 250
254/* Wait for something to read, read it, then clear the bit */ 251/* Wait for something to read, read it, then clear the bit */
@@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = {
257 unsigned int i; \ 254 unsigned int i; \
258 value = 0; \ 255 value = 0; \
259 for (i = 0; i < 10000; i++) { \ 256 for (i = 0; i < 10000; i++) { \
260 if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \ 257 if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \
261 break; \ 258 break; \
262 udelay(1); \ 259 udelay(1); \
263 } \ 260 } \
264 value = driver->regs->uctrl_data; \ 261 value = sbus_readl(&driver->regs->uctrl_data); \
265 dprintk(("read data 0x%02x\n", value)); \ 262 dprintk(("read data 0x%02x\n", value)); \
266 driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \ 263 sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \
267} 264}
268 265
269static void uctrl_do_txn(struct uctrl_txn *txn) 266static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn)
270{ 267{
271 struct uctrl_driver *driver = &drv;
272 int stat, incnt, outcnt, bytecnt, intr; 268 int stat, incnt, outcnt, bytecnt, intr;
273 u32 byte; 269 u32 byte;
274 270
275 stat = driver->regs->uctrl_stat; 271 stat = sbus_readl(&driver->regs->uctrl_stat);
276 intr = driver->regs->uctrl_intr; 272 intr = sbus_readl(&driver->regs->uctrl_intr);
277 driver->regs->uctrl_stat = stat; 273 sbus_writel(stat, &driver->regs->uctrl_stat);
278 274
279 dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr)); 275 dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr));
280 276
@@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn)
305 } 301 }
306} 302}
307 303
308static void uctrl_get_event_status(void) 304static void uctrl_get_event_status(struct uctrl_driver *driver)
309{ 305{
310 struct uctrl_driver *driver = &drv;
311 struct uctrl_txn txn; 306 struct uctrl_txn txn;
312 u8 outbits[2]; 307 u8 outbits[2];
313 308
@@ -317,7 +312,7 @@ static void uctrl_get_event_status(void)
317 txn.inbuf = NULL; 312 txn.inbuf = NULL;
318 txn.outbuf = outbits; 313 txn.outbuf = outbits;
319 314
320 uctrl_do_txn(&txn); 315 uctrl_do_txn(driver, &txn);
321 316
322 dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); 317 dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
323 driver->status.event_status = 318 driver->status.event_status =
@@ -325,9 +320,8 @@ static void uctrl_get_event_status(void)
325 dprintk(("ev is %x\n", driver->status.event_status)); 320 dprintk(("ev is %x\n", driver->status.event_status));
326} 321}
327 322
328static void uctrl_get_external_status(void) 323static void uctrl_get_external_status(struct uctrl_driver *driver)
329{ 324{
330 struct uctrl_driver *driver = &drv;
331 struct uctrl_txn txn; 325 struct uctrl_txn txn;
332 u8 outbits[2]; 326 u8 outbits[2];
333 int i, v; 327 int i, v;
@@ -338,7 +332,7 @@ static void uctrl_get_external_status(void)
338 txn.inbuf = NULL; 332 txn.inbuf = NULL;
339 txn.outbuf = outbits; 333 txn.outbuf = outbits;
340 334
341 uctrl_do_txn(&txn); 335 uctrl_do_txn(driver, &txn);
342 336
343 dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); 337 dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
344 driver->status.external_status = 338 driver->status.external_status =
@@ -354,71 +348,101 @@ static void uctrl_get_external_status(void)
354 348
355} 349}
356 350
357static int __init ts102_uctrl_init(void) 351static int __devinit uctrl_probe(struct of_device *op,
352 const struct of_device_id *match)
358{ 353{
359 struct uctrl_driver *driver = &drv; 354 struct uctrl_driver *p;
360 int len; 355 int err = -ENOMEM;
361 struct linux_prom_irqs tmp_irq[2];
362 unsigned int vaddr[2] = { 0, 0 };
363 int tmpnode, uctrlnode = prom_getchild(prom_root_node);
364 int err;
365 356
366 tmpnode = prom_searchsiblings(uctrlnode, "obio"); 357 p = kzalloc(sizeof(*p), GFP_KERNEL);
358 if (!p) {
359 printk(KERN_ERR "uctrl: Unable to allocate device struct.\n");
360 goto out;
361 }
367 362
368 if (tmpnode) 363 p->regs = of_ioremap(&op->resource[0], 0,
369 uctrlnode = prom_getchild(tmpnode); 364 resource_size(&op->resource[0]),
365 "uctrl");
366 if (!p->regs) {
367 printk(KERN_ERR "uctrl: Unable to map registers.\n");
368 goto out_free;
369 }
370 370
371 uctrlnode = prom_searchsiblings(uctrlnode, "uctrl"); 371 p->irq = op->irqs[0];
372 err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
373 if (err) {
374 printk(KERN_ERR "uctrl: Unable to register irq.\n");
375 goto out_iounmap;
376 }
372 377
373 if (!uctrlnode) 378 err = misc_register(&uctrl_dev);
374 return -ENODEV; 379 if (err) {
380 printk(KERN_ERR "uctrl: Unable to register misc device.\n");
381 goto out_free_irq;
382 }
375 383
376 /* the prom mapped it for us */ 384 sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr);
377 len = prom_getproperty(uctrlnode, "address", (void *) vaddr, 385 printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n",
378 sizeof(vaddr)); 386 op->node->full_name, p->regs, p->irq);
379 driver->regs = (struct uctrl_regs *)vaddr[0]; 387 uctrl_get_event_status(p);
388 uctrl_get_external_status(p);
380 389
381 len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq, 390 dev_set_drvdata(&op->dev, p);
382 sizeof(tmp_irq)); 391 global_driver = p;
383 392
384 /* Flush device */ 393out:
385 READUCTLDATA(len); 394 return err;
386 395
387 if(!driver->irq) 396out_free_irq:
388 driver->irq = tmp_irq[0].pri; 397 free_irq(p->irq, p);
389 398
390 err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); 399out_iounmap:
391 if (err) { 400 of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
392 printk("%s: unable to register irq %d\n",
393 __func__, driver->irq);
394 return err;
395 }
396 401
397 if (misc_register(&uctrl_dev)) { 402out_free:
398 printk("%s: unable to get misc minor %d\n", 403 kfree(p);
399 __func__, uctrl_dev.minor); 404 goto out;
400 free_irq(driver->irq, driver); 405}
401 return -ENODEV;
402 }
403 406
404 driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; 407static int __devexit uctrl_remove(struct of_device *op)
405 printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq); 408{
406 uctrl_get_event_status(); 409 struct uctrl_driver *p = dev_get_drvdata(&op->dev);
407 uctrl_get_external_status(); 410
408 return 0; 411 if (p) {
412 misc_deregister(&uctrl_dev);
413 free_irq(p->irq, p);
414 of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
415 kfree(p);
416 }
417 return 0;
409} 418}
410 419
411static void __exit ts102_uctrl_cleanup(void) 420static struct of_device_id uctrl_match[] = {
421 {
422 .name = "uctrl",
423 },
424 {},
425};
426MODULE_DEVICE_TABLE(of, uctrl_match);
427
428static struct of_platform_driver uctrl_driver = {
429 .name = "uctrl",
430 .match_table = uctrl_match,
431 .probe = uctrl_probe,
432 .remove = __devexit_p(uctrl_remove),
433};
434
435
436static int __init uctrl_init(void)
412{ 437{
413 struct uctrl_driver *driver = &drv; 438 return of_register_driver(&uctrl_driver, &of_bus_type);
439}
414 440
415 misc_deregister(&uctrl_dev); 441static void __exit uctrl_exit(void)
416 if (driver->irq) 442{
417 free_irq(driver->irq, driver); 443 of_unregister_driver(&uctrl_driver);
418 if (driver->regs)
419 driver->regs = NULL;
420} 444}
421 445
422module_init(ts102_uctrl_init); 446module_init(uctrl_init);
423module_exit(ts102_uctrl_cleanup); 447module_exit(uctrl_exit);
424MODULE_LICENSE("GPL"); 448MODULE_LICENSE("GPL");