Subject: Re: Getting the IRQ number (Was: Basic driver devel questions ?)

From: Michael Ellerman <[email-masked]>
Date: Thu, 09 Dec 2010 00:45:10 +1100

On Wed, 2010-12-08 at 11:18 +0100, Guillaume Dargaud wrote:
> Thanks again for your detailed answer,
> I'm learning, but not as fast as my colleagues with a deadline want me to !

:)

> > The platform code does that. That function create devices on the
> > platform bus by examining the device tree. It looks for nodes that are
> > compatible with the compatible strings you give it, and treats them as
> > busses, ie. creates devices for all child nodes of those nodes.
> 
> Is there a way to enable some debug output from it, to see what's going on ?

Not really, but there probably should be.

> > > ...hmm I had to "git pull" in order for this to compile your snippet.
> > > That's really recent! Unfortunately i need to reflash my device with the
> > > new kernel before i can begin testing my module.
> > 
> > It shouldn't be that recent, what kernel version were you using?
> 
> I had to go from 2.6.34 to 2.6.35, xilinx git tree.

Ah that is the problem I think.

Sorry I assumed you were working on mainline. In 2.6.35 you still need
to use an of_platform_driver, I'll describe below.

> > platform_device_register() tends to be for cases where you can't
> > discover or probe a device, but you "know" that it exists.
> 
> When you see something in /sys/devices/plb.0/, it means that you don't need 
> platform_device_register, right ?

That's right.

> > Yes, "make tags", then use vim :)
> 
> Great, that works.

Cool.

> OK, here's the relevant part of my code, ripped directly from your sample, 
> with a few additions and different variable names. Why do you think 
> xad_driver_probe() is not being called ?

As I said above in 2.6.35 platform drivers and of_platform drivers were
still separate. So your device is on the of_platform_bus (ie. was
discovered using the device tree), but your driver is on the
platform_bus. Yes this is very confusing.

So basically you need to change all occurrences of platform_driver to
of_platform_driver.

> #include <linux/kernel.h>
> #include <linux/init.h>
> #include <asm/device.h>
> #include <linux/platform_device.h>
> #include <linux/cdev.h>         // char device
> #include <linux/fs.h>
> #include <linux/of.h>
> #include <linux/interrupt.h>
> 
> #define DEVNAME "xps-acqui-data"
> #define NAME "xad"              // This is only used for printk
> 
> #define SD "{%s %d} "
> #define FL , __func__, __LINE__
> 
> static dev_t first;
> static unsigned int count = 1;
> static int my_major = 241, my_minor = 0;
> // You must run "mknod /dev/xad c 241 0" in a shell at least once
> 
> struct cdev *my_cdev=NULL;
> struct platform_device *pdev=NULL;
> 
> typedef struct XadDevice {
>   struct resource *hw_region;
>   struct device *dev;
>   int irq;
> } tXadDevice;
> tXadDevice Xad;
> 
> // There should be something in:
> // ll /sys/devices/plb.0/c9800000.xps-acqui-data
> static const struct of_device_id xad_device_id[] = {                       
>         { .compatible     = "xlnx,xps-acqui-data-3.00.a" },     // Must match 
> the DTS
>         {}
> };
> 
>   
> static irqreturn_t XadIsr(int irq, void *dev_id) {
>   printk(KERN_INFO SD "IRQ:%d\n" FL, irq);
>   return IRQ_HANDLED;
> }
> 
> ///////////////////////////////////////////////////////////////////////////////
> // Platform Bus Support
> ///////////////////////////////////////////////////////////////////////////////
> 
> static int  xad_driver_probe(struct platform_device *device /*,
>                             const struct of_device_id *device_id*/ ) {

So you need to switch the prototype here to:

static int xad_driver_probe(struct of_platform_device *ofdev,
                            const struct of_device_id *device_id) {

>   struct device_node *dn = device->dev.of_node;
>   int rc;
> 
>   pr_devel("Probing %s\n", dn->full_name);
>   
>   Xad.irq = irq_of_parse_and_map(dn, 0);
>   rc=request_irq(Xad.irq, XadIsr, IRQF_TRIGGER_RISING  | IRQF_DISABLED, 
> "XadIsr", &Xad);
>   if (rc) printk(KERN_INFO SD "Failled IRQ request: %d\n" FL, rc);
>   
>   return 0;
> }
> 
> static int __devexit xad_driver_remove(struct platform_device *device) {
>   printk(KERN_INFO SD "Removing...\n" FL);
>   return 0;
> }
> 
> static struct platform_driver xad_driver = {

Becomes of_platform_driver

>   .probe  = xad_driver_probe,
>   .remove = xad_driver_remove,
>   .driver = {
>     .owner = THIS_MODULE,
>     .name = "xad-driver",
>         .of_match_table = xad_device_id,
>   },
> };
> 
> 
> ///////////////////////////////////////////////////////////////////////////////
> // This section deals with the /dev/xad device
> ///////////////////////////////////////////////////////////////////////////////
> static int xad_open(struct inode *node, struct file *filep) {
>   printk (KERN_INFO SD "OPENING device: %s\n" FL, NAME);
>   return 0;
> }
> 
> static int xad_release(struct inode *node, struct file *filep) {
>   printk (KERN_INFO SD "RELEASING device: %s\n" FL, NAME);
>   return 0;
> }
> 
> static int  xad_ioctl(struct inode *node, struct file *filep, unsigned int cmd, 
> unsigned long arg) {
>   printk (KERN_INFO SD "IOCTL on device: %s, cmd:%d, arg:%lu\n" FL, NAME, cmd, 
> arg);
>   return 0;
> }
> 
> static struct file_operations fops = {
>   .owner   = THIS_MODULE,
>   .open    = xad_open,
>   .release = xad_release,
>   .ioctl   = xad_ioctl,
> };
> 
> 
> ///////////////////////////////////////////////////////////////////////////////
> // Called on insmod
> static int __init xad_init(void) {
>   int rc=0;
>   printk(KERN_INFO SD "Module %s: loading...\n" FL, NAME);
>   
>   // Deal with the device
>   first = MKDEV (my_major, my_minor);
>   register_chrdev_region(first, count, DEVNAME);
>   my_cdev = cdev_alloc ();
>   if (NULL==my_cdev) goto Err;
>   
>   cdev_init(my_cdev, &fops);
>   cdev_add (my_cdev, first, count);
> 
>   printk(KERN_INFO SD "Module %s: Major=%d, Minor=%d, Count=%d\n" FL, NAME, 
> my_major, my_minor, count);
> 
>   // Driver
>   rc = platform_driver_register(&xad_driver);

Should be of_register_platform_driver()

> //  rc = platform_driver_probe(&xad_driver, xad_driver_probe);
>   if (rc) goto err_plat;
> 
>   // Device
>   pdev=platform_device_register_simple("xps-acqui-data", -1, NULL, 0);
>   if (IS_ERR(pdev)) {
>           rc = PTR_ERR(pdev);
>           platform_driver_unregister(&xad_driver);
>           goto err_plat;
>   }
> 
> 
>   return 0;
> 
> err_plat:
>   unregister_chrdev_region(first, count);
> Err:
>   printk(KERN_ERR SD "Module %s: Failed loading rc=%d\n" FL, NAME, rc);
>   return rc;
> }
> 
> ///////////////////////////////////////////////////////////////////////////////
> // Called on rmmod
> static void xad_exit(void) {
>   platform_device_unregister(pdev); pdev=NULL;
>   platform_driver_unregister(&xad_driver);
>   
>   cdev_del (my_cdev); my_cdev=NULL;
>   unregister_chrdev_region (first, count);
>   printk(KERN_INFO SD "Module %s unloaded\n" FL, NAME);
> }
> 
> module_init(xad_init);
> module_exit(xad_exit);
> 
> MODULE_AUTHOR("Guillaume Dargaud");
> MODULE_LICENSE("GPL");
> 
> 

cheers