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

From: Michael Ellerman <[email-masked]>
Date: Mon, 06 Dec 2010 16:29:00 +1100

On Fri, 2010-12-03 at 15:58 +0100, Guillaume Dargaud wrote:
> > No. of_platform_drivers are more/less obsolete. Normal platform drivers
> > can now be associated with a device-tree node just fine.
> 
> OK.
> 
> If my dts definition is thus:
> 		xps_acqui_data_0: xps-acqui-data@c9800000 {
> 			compatible = "xlnx,xps-acqui-data-3.00.a";
> 			interrupt-parent = <&xps_intc_0>;
> 			interrupts = < 0 2 >;
> 			reg = < 0xc9800000 0x10000 >;
> 			xlnx,family = "virtex4";
> 			xlnx,include-dphase-timer = <0x1>;
> 			xlnx,mplb-awidth = <0x20>;
> 			xlnx,mplb-clk-period-ps = <0x2710>;
> 			xlnx,mplb-dwidth = <0x40>;
> 			xlnx,mplb-native-dwidth = <0x40>;
> 			xlnx,mplb-p2p = <0x0>;
> 			xlnx,mplb-smallest-slave = <0x20>;
> 		} ;
> 
> What are the names I need to pass to platform_driver_register and 
> platform_device_register_simple ? xps_acqui_data_0, xps-acqui-data or xps-
> acqui-data-3.00.a ?

None of the above :)  xps_acqui_data_0 is a label, it is only relevant
within the dts source, ie. other nodes may refer to this node by that
label. But the label string is not useful in Linux. The node name
"xps-acqui-data" is visible in Linux, but is generally not used for
discovery, it's just a name. What you do want to use is the full
compatible value, ie. "xlnx,xps-acqui-data-3.00.a".

> Why is there not a word about the functions platform_*_register in my various 
> driver books ? LDD 3rd ed (O'Reilly), Writing LDD (Cooperstein) or LKD 
> (Love)... Is it something specific to powerpc and the books are oriented x86 ? 

Because they're old dead-tree references, that aren't up to date with
the kernel. The LDD website says "LDD3 is current as of the 2.6.10
kernel", that's 25 kernel versions ago! I'm also not aware of any book
that has information on anything other than x86 drivers.

> What's a good source, besides grepping the kernel to no end ?

Nothing really I'm afraid.

So you have a device, it appears in your device tree, and you want to
write a driver for it.

The first issue is that someone needs to create a device for your node,
it doesn't necessarily happen by default. For many platforms this will
all happen "automagically" as long as the device node that describes
your device appears in the right place, but I'll describe it in full
anyway.

In most cases your device will appear below a node that represents a
bus, eg:

	foobus@xyz {
		compatible = "vendor,foobus-v1.m.n", "simple-bus";
		...
		yournode@abc {
			...
		}
	}

If that isn't the case you need to arrange for it somehow [1]. 

Somewhere there needs to be code to probe that bus and create devices on
it. That is usually done in platform code with of_platform_bus_probe(). 

If you don't know what platform you're on, you can look at a boot log
for a line saying "Using <blah> machine description", it will be very
early in the log. "blah" is then the name of the platform you're on, and
you should be able to grep for it in arch/powerpc/platforms.

Once you've found the .c file for your platform, there should be a call
somewhere to of_platform_bus_probe(), with a list of ids, and one of
those ids should match the compatible property of your bus node. In a
lot of cases that is just "simple-bus".

To check a device is being created for your device node, you can look
in /sys/devices. The device names don't match 100% with what's in the
device tree, but the name should be there, so in your case:

# find /sys/devices -name '*xps-acqui-data*'

Assuming that is working you can start on the driver side of things. A
rough template is:

static int foo_driver_probe(struct platform_device *device,
			    const struct of_device_id *device_id)
{
	struct device_node *dn = device->dev.of_node;
	struct foo_device *foo;

	pr_devel("%s: probing %s\n", __func__, dn->full_name);
	
	/* Check you really want to probe this device and everything is OK */

	foo = kzalloc(sizeof(*foo));
	if (!foo)
		return -ENOMEM;

	foo->regs = of_iomap(dn, 0);
	if (!foo->regs)
		goto out;

	foo->irq = irq_of_parse_and_map(dn, 0);
	if (foo->irq == NO_IRQ)
		goto out;

	etc.

	return 0;
}

static const struct of_device_id foo_device_id[] =
{                       
        { .compatible     = "vendor,foo-device" },
        {}
};

static struct platform_driver foo_driver = {
        .probe          = foo_driver_probe,
        .driver = {
                .name = "foo-driver",
                .owner = THIS_MODULE,
                .of_match_table = foo_device_id,
        },          
};

static int __init foo_driver_init(void)
{
        return platform_driver_register(&foo_driver);
}
module_init(foo_driver_init);

I probably missed something there, I haven't compiled it (obviously),
but it's a start. Some of this stuff is in flux, but I think everything
I have above is OK at least for now. Grant might correct me :)

cheers

[1]: One option is to put your device under an existing bus, but only if
that (fairly) accurately represents the hardware topology. You might
need to create a new node representing the bus your device appears on.
You can also manually create the device in C, but that is generally not
the right approach unless the device tree is immutable - ie. comes from
firmware that you don't control.