diff mbox

Fwd: Hid over I2C and ACPI interaction

Message ID 1341471717.1682.125.camel@rui.sh.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Zhang, Rui July 5, 2012, 7:01 a.m. UTC
> -------- Original Message --------
> Subject: Hid over I2C and ACPI interaction
> Date: Wed, 4 Jul 2012 15:46:35 +0200
> From: Benjamin Tissoires <benjamin.tissoires@gmail.com>
> To: Jean Delvare <khali@linux-fr.org>, Ben Dooks <ben-linux@fluff.org>, Wolfram 
> Sang <w.sang@pengutronix.de>, Len Brown <lenb@kernel.org>, 
> <linux-acpi@vger.kernel.org>, <linux-i2c@vger.kernel.org>, 
> <linux-kernel@vger.kernel.org>
> CC: Jiri Kosina <jkosina@suse.cz>, Stéphane Chatty <chatty@enac.fr>, JJ Ding 
> <jj_ding@emc.com.tw>
> 
> Hi Guys,
> 
> I'm the co-author and the maintainer of the hid-multitouch driver. To
> support even more devices, I started the implementation of the HID
> over I2C protocol specification which is introduced by Win8. I'm quite
> comfortable with the hid and the I2C part, but I'm blocked with the
> interaction with the ACPI for the pnp part.
> 
> I wanted to have your advice/help on this problem. I've add in the
> recipients list the maintainers of i2c and ACPI, sorry for the noise
> if you don't feel concerned about this.
> 
> So, let's go deeper in the problem ;-)
> Microsoft's spec asks the OEM to fill the ACPI DSDT to provide the
> following scope in the ASL layout:
> 
> >>>>>>>>> begin of ASL
> Scope (\_SB) {
> //--------------------
> //  General Purpose I/O, ports 0...127
> //--------------------
> 
> Device(HIDI2C_DEVICE1) {
>      Name(_ADR,0)
>      Name (_HID, "MSFT1234”)
>      Name (_CID, "PNP0C50")
>      Name (_UID, 3)
> 
>      Method(_CRS, 0x0, NotSerialized)
>      {
>          Name (RBUF, ResourceTemplate ()
>          {
>          // Address 0x07 on I2C-X (OEM selects this address)
>         //IHV SPECIFIC I2C3 = I2C Controller; TGD0 = GPIO Controller;
>          I2CSerialBus (0x07, ControllerInitiated,
> 100000,AddressingMode7Bit, "\\_SB.I2C3",,,,)
>          GpioInt(Level, ActiveLow, Exclusive, PullUp, 0, "\\_SB. TGD0",
> 0 , ResourceConsumer, , ) {40}
>          })
>       Return(RBUF)
>       }
> 
>       Method(_DSM, 0x4, NotSerialized)
>       {
>          // BreakPoint
>          Store ("Method _DSM begin", Debug)
> 
>          // DSM UUID
>          switch(ToBuffer(Arg0))
>          {		
>              // ACPI DSM UUID for HIDI2C
>              case(ToUUID("3CDFF6F7-4267-4555-AD05-B30A3D8938DE"))
>              {
>                   // DSM function which returns the HID Descriptor
> Address (skipped)
>              }
> 
>              default
>              {
>                  // No other GUIDs supported
>                  Return(Buffer(One) { 0x00 })
>              }
>          }
>      }
> }
> <<<<<<<<< end of ASL
> 
yep, this is an ACPI enumerated I2C controller.

> Summary:
> - a HID over I2C device has to present the Compatibility ID "PNP0C50"
> - in the _CRS block, the address, the adapter and the gpioInt are
> defined (or referenced)
> - it presents a Device Specific Method (_DSM) which returns the HID
> Descriptor register address. This register is our entry point for
> retrieving the information about our hid device (so it's mandatory to
> obtain it).
> 
> Where am I:
> - I've written a first layer on top of i2c that retrieves the hid
> register (currently the address 0x0001 is hardcoded), then get the
> report desccriptors and the input events, and forward all this stuff
> to the hid layer.
> - It's working with a custom emulated HID over i2c touchpad, while
> waiting for the one a manufacturer should send to me.
> - The detection and the addition to the adapter is done by adding the
> address in the lists and the name through the i2c "->detect" callback
> (which is not very good, because I don't have the interrupt line
> there).
> - I've written a first acpi implementation that rely on the
> DEVICE_ACPI_HANDLE macro to get the ACPI handle of the device (if
> available).
> - I'm not able to do some tests with the ACPI, as I don't know how to
> implement this DSDT on my computer (I'm missing the I2C part), and the
> manufacturer returned the mainboard with the right DSDT to the OEM.
> 
> My questions:
> - will the current acpi implementation handle I2C devices?

you still need to write your own device driver for the device.

> - it seems to me that the .archdata field is left blank during the i2c
> device initialization in all paths I've seen. Is that true?
> - who puts the name int the struct i2c_board_info? (for hot-plugged
> i2c devices).
> 
> - finally, what is the best way of handling ACPI for those I2C devices:
>    1) everything is fine, I should have the ACPI handle in .archdata.
>    2) someone has to implement the handling of I2C in the pnpACPI layer
> (by adding I2CSerialBus handling and creating there the i2c slave).
>    3) I should create an acpi driver which handles "PNP0C50" and which
> creates the i2c slaves.
> 
exactly.

As this I2C controller uses the GPIO interrupt, we need an ACPI GPIO
controller driver for interrupts first.
I already have such a patch in hand, but have not release it for some
reason.
Second, you need to write your own PNP I2C controller driver, to
enumerate the I2C controller via ACPI, AND enumerate the I2C slave
devices under this controller to I2C bus. I also have a similar driver
for SPI controller and SD/MMC controller.
Third, you need a I2C slave device driver to handle the I2C slave device
in I2C bus.

here is a BKM I wrote, hope it helps.

And also any comments are welcome. :)

From 0a0fa4ff7b4b06c6560de94a78b15c6adfd86e34 Mon Sep 17 00:00:00 2001
From: Zhang Rui <rui.zhang@intel.com>
Date: Mon, 26 Dec 2011 10:42:04 +0800

 As many SoC IP blocks are not hardware self-enumerable, the
 firmware, aka, ACPI tables, is responsible for
 enumerating/reserving/assigning system resources to these
 devices. This tutorial talks about how to enumerate these
 devices via ACPI namespace.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 Documentation/acpi/acpi-device-probing.txt |  466
++++++++++++++++++++++++++++
 1 file changed, 466 insertions(+)
 create mode 100644 Documentation/acpi/acpi-device-probing.txt

+platform attached if you suspect it's an BIOS problem.
+
+4.2 Some important ACPICA APIs for device driver implementation:
+
+-- acpi_status
+   acpi_walk_namespace(acpi_object_type type,
+		       acpi_handle start_object,
+		       u32 max_depth,
+		       acpi_walk_callback pre_order_visit,
+		       acpi_walk_callback post_order_visit,
+		       void *context, void **return_value);
+Traverse ACPI namespace subtree rooted at start_object, go down
max_depth level
+at most. Call pre_order_visit when the proper node with type is found
the first
+time, call post_order_visit is the node is previously visited. Context
and
+return_value is passed down during the traverse.
+
+And the prototype of acpi_walk_callback:
+typedef
+acpi_status(*acpi_walk_callback) (acpi_handle object,
+				  u32 nesting_level,
+				  void *context, void **return_value);
+
+-- acpi_status
+   acpi_get_handle(acpi_handle parent,
+   		   acpi_string pathname, acpi_handle * ret_handle);
+Try to get handle with specified pathname under node parent. Usually
used to
+check whether a particular node is available or not.
+
+-- acpi_status
+   acpi_get_object_info(acpi_handle object,
+		        struct acpi_device_info **return_buffer);
+Get acpi_device_info from object handle. Useful for retrieving ACPI
object
+name, type, and status etc.
+
+-- acpi_status
+   acpi_walk_resources(acpi_handle device,
+		       char *name,
+	    	       acpi_walk_resource_callback user_function, void *context);
+Traverse resource node specified by name(e.g. METHOD_NAME__CRS) in ACPI
+namespace subtree rooted at device. Call user_function for each entry
in
+acpi_resource list. The list may containe acpi_resource entries with
various
+types. So it is important to handle the interested resource type
properly.
+The acpi_resource with ACPI_RESOURCE_TYPE_END_TAG indicates
end-of-list.
+
+And the prototype of acpi_walk_resource_callback:
+typedef
+acpi_status(*acpi_walk_resource_callback) (struct acpi_resource *
resource,
+					   void *context);
+
+More ACPICA external interfaces available in include/acpi/acpixf.h

Comments

Zhang, Rui July 5, 2012, 7:20 a.m. UTC | #1
Hah, seems I forgot to reply to Benjamin.

On ?, 2012-07-05 at 15:01 +0800, Zhang Rui wrote:
> > -------- Original Message --------
> > Subject: Hid over I2C and ACPI interaction
> > Date: Wed, 4 Jul 2012 15:46:35 +0200
> > From: Benjamin Tissoires <benjamin.tissoires@gmail.com>
> > To: Jean Delvare <khali@linux-fr.org>, Ben Dooks <ben-linux@fluff.org>, Wolfram 
> > Sang <w.sang@pengutronix.de>, Len Brown <lenb@kernel.org>, 
> > <linux-acpi@vger.kernel.org>, <linux-i2c@vger.kernel.org>, 
> > <linux-kernel@vger.kernel.org>
> > CC: Jiri Kosina <jkosina@suse.cz>, Stéphane Chatty <chatty@enac.fr>, JJ Ding 
> > <jj_ding@emc.com.tw>
> > 
> > Hi Guys,
> > 
> > I'm the co-author and the maintainer of the hid-multitouch driver. To
> > support even more devices, I started the implementation of the HID
> > over I2C protocol specification which is introduced by Win8. I'm quite
> > comfortable with the hid and the I2C part, but I'm blocked with the
> > interaction with the ACPI for the pnp part.
> > 
> > I wanted to have your advice/help on this problem. I've add in the
> > recipients list the maintainers of i2c and ACPI, sorry for the noise
> > if you don't feel concerned about this.
> > 
> > So, let's go deeper in the problem ;-)
> > Microsoft's spec asks the OEM to fill the ACPI DSDT to provide the
> > following scope in the ASL layout:
> > 
> > >>>>>>>>> begin of ASL
> > Scope (\_SB) {
> > //--------------------
> > //  General Purpose I/O, ports 0...127
> > //--------------------
> > 
> > Device(HIDI2C_DEVICE1) {
> >      Name(_ADR,0)
> >      Name (_HID, "MSFT1234”)
> >      Name (_CID, "PNP0C50")
> >      Name (_UID, 3)
> > 
> >      Method(_CRS, 0x0, NotSerialized)
> >      {
> >          Name (RBUF, ResourceTemplate ()
> >          {
> >          // Address 0x07 on I2C-X (OEM selects this address)
> >         //IHV SPECIFIC I2C3 = I2C Controller; TGD0 = GPIO Controller;
> >          I2CSerialBus (0x07, ControllerInitiated,
> > 100000,AddressingMode7Bit, "\\_SB.I2C3",,,,)
> >          GpioInt(Level, ActiveLow, Exclusive, PullUp, 0, "\\_SB. TGD0",
> > 0 , ResourceConsumer, , ) {40}
> >          })
> >       Return(RBUF)
> >       }
> > 
> >       Method(_DSM, 0x4, NotSerialized)
> >       {
> >          // BreakPoint
> >          Store ("Method _DSM begin", Debug)
> > 
> >          // DSM UUID
> >          switch(ToBuffer(Arg0))
> >          {		
> >              // ACPI DSM UUID for HIDI2C
> >              case(ToUUID("3CDFF6F7-4267-4555-AD05-B30A3D8938DE"))
> >              {
> >                   // DSM function which returns the HID Descriptor
> > Address (skipped)
> >              }
> > 
> >              default
> >              {
> >                  // No other GUIDs supported
> >                  Return(Buffer(One) { 0x00 })
> >              }
> >          }
> >      }
> > }
> > <<<<<<<<< end of ASL
> > 
> yep, this is an ACPI enumerated I2C controller.
> 
> > Summary:
> > - a HID over I2C device has to present the Compatibility ID "PNP0C50"
> > - in the _CRS block, the address, the adapter and the gpioInt are
> > defined (or referenced)
> > - it presents a Device Specific Method (_DSM) which returns the HID
> > Descriptor register address. This register is our entry point for
> > retrieving the information about our hid device (so it's mandatory to
> > obtain it).
> > 
> > Where am I:
> > - I've written a first layer on top of i2c that retrieves the hid
> > register (currently the address 0x0001 is hardcoded), then get the
> > report desccriptors and the input events, and forward all this stuff
> > to the hid layer.
> > - It's working with a custom emulated HID over i2c touchpad, while
> > waiting for the one a manufacturer should send to me.
> > - The detection and the addition to the adapter is done by adding the
> > address in the lists and the name through the i2c "->detect" callback
> > (which is not very good, because I don't have the interrupt line
> > there).
> > - I've written a first acpi implementation that rely on the
> > DEVICE_ACPI_HANDLE macro to get the ACPI handle of the device (if
> > available).
> > - I'm not able to do some tests with the ACPI, as I don't know how to
> > implement this DSDT on my computer (I'm missing the I2C part), and the
> > manufacturer returned the mainboard with the right DSDT to the OEM.
> > 
> > My questions:
> > - will the current acpi implementation handle I2C devices?
> 
> you still need to write your own device driver for the device.
> 
> > - it seems to me that the .archdata field is left blank during the i2c
> > device initialization in all paths I've seen. Is that true?
> > - who puts the name int the struct i2c_board_info? (for hot-plugged
> > i2c devices).
> > 
> > - finally, what is the best way of handling ACPI for those I2C devices:
> >    1) everything is fine, I should have the ACPI handle in .archdata.
> >    2) someone has to implement the handling of I2C in the pnpACPI layer
> > (by adding I2CSerialBus handling and creating there the i2c slave).
> >    3) I should create an acpi driver which handles "PNP0C50" and which
> > creates the i2c slaves.
> > 
> exactly.
> 
> As this I2C controller uses the GPIO interrupt, we need an ACPI GPIO
> controller driver for interrupts first.
> I already have such a patch in hand, but have not release it for some
> reason.
> Second, you need to write your own PNP I2C controller driver, to
> enumerate the I2C controller via ACPI, AND enumerate the I2C slave
> devices under this controller to I2C bus. I also have a similar driver
> for SPI controller and SD/MMC controller.
> Third, you need a I2C slave device driver to handle the I2C slave device
> in I2C bus.
> 
> here is a BKM I wrote, hope it helps.
> 
> And also any comments are welcome. :)
> 
> From 0a0fa4ff7b4b06c6560de94a78b15c6adfd86e34 Mon Sep 17 00:00:00 2001
> From: Zhang Rui <rui.zhang@intel.com>
> Date: Mon, 26 Dec 2011 10:42:04 +0800
> 
>  As many SoC IP blocks are not hardware self-enumerable, the
>  firmware, aka, ACPI tables, is responsible for
>  enumerating/reserving/assigning system resources to these
>  devices. This tutorial talks about how to enumerate these
>  devices via ACPI namespace.
> 
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> ---
>  Documentation/acpi/acpi-device-probing.txt |  466
> ++++++++++++++++++++++++++++
>  1 file changed, 466 insertions(+)
>  create mode 100644 Documentation/acpi/acpi-device-probing.txt
> 
> diff --git a/Documentation/acpi/acpi-device-probing.txt
> b/Documentation/acpi/acpi-device-probing.txt
> new file mode 100644
> index 0000000..82efbf3
> --- /dev/null
> +++ b/Documentation/acpi/acpi-device-probing.txt
> @@ -0,0 +1,466 @@
> +
> +HOWTO enumerate devices via ACPI
> +
> +Copyright (c) 2011-2012 Intel Corporation
> +
> +Contrast to hardware self-enumerable devices(e.g. USB, PCI) on PC
> platform,
> +many SoC IP blocks can not be self enumerated.
> +We used to introduce platform specific code for these devices.
> +But now, with ACPI 5.0, there is no requirement for the hardware to be
> +self-discoverable, enumerable or re-locatable, as the firmware is
> responsible
> +for enumerating/reserving/assigning system resources (such as address
> ranges or
> +interrupts) to the device.
> +
> +This document will show how to enumerate and configure a device via
> ACPI.
> +If you want to get more details about why and when we need this,
> +please refer to ACPI spec 5.0 and
> +Intel Architecture Platform Compatibility Definition.
> +
> +Note that although these are ACPI devices, we prefer to use PnP drivers
> for them,
> +this is because:
> +1. all the non-ACPI-predefined Devices are exported as PnP devices as
> well
> +2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
> work
> +   for the device driver, e.g. getting & parsing ACPI resources.
> +
> +=============================================================================
> +1. Understand device definition in ACPI namespace
> +   [Case study 1] SD/MMC controller
> +2. Driver for a leaf device
> +   2.1 Make a list of supported PnP ids
> +   2.2 Implement .probe/.remove callbacks for the PnP driver
> +   2.3 Fill in the pnp_driver structure
> +   2.4 Register the PnP driver
> +3. Driver for a master device on a non-self-enumerable bus
> +   [Case Study 2] SPI controller and its slave device
> +   3.1 Probe the master device
> +   3.2 Walk ACPI namesapce to get the child devices of the master
> device
> +   3.3 Register these child devices as slave devices
> +   3.4 Write slave device driver
> +4. Misc
> +=============================================================================
> +
> +-----------------------------------------------------------------------------
> +1. Understand device definition in ACPI namespace
> +-----------------------------------------------------------------------------
> +
> +To enumerate a device in ACPI namespace, we need to find out and
> understand
> +HOW the device is defined in ACPI namespace first.
> +
> +[Case study 1 ] SD/MMC Controller
> +
> +Here is an ASL example code for SD/MMC controller definition in ACPI
> namespace.
> +
> +        Device (EMMC)
> +        {
> +            Name (_ADR, Zero)
> +            /* I use PNPXXXX, an arbitrary string, here, as PnP id is
> device specific */
> +            Name (_HID, "PNPXXXX")
> +            Name (_CID, "PNPXXXX")
> +            Name (_UID, 4)
> +
> +            Method (_CRS, 0, NotSerialized)
> +            {
> +                Name (RBUF, ResourceTemplate ()
> +                {
> +                    Memory32Fixed (ReadWrite,
> +                        0xFFA50000,         // Address Base
> +                        0x00000100,         // Address Length
> +                        )
> +                    Interrupt (ResourceConsumer, Level, ActiveLow,
> Exclusive, ,, )
> +                    {
> +                        0x0000001b,
> +                    }
> +                })
> +                Return (RBUF)
> +            }
> +
> +            Method (_STA, 0, NotSerialized)
> +            {
> +                Return (0x0F)
> +            }
> +        }
> +
> +_ADR : the address of this device on its parent bus. Useless in this
> case.
> +_HID : the PnP id for this device.
> +_CID : the compatible PnP id. use this as the PnP id if _HID doesn't
> exist.
> +_CRS : the system resources currently allocated to this device.
> +       the Memory32Fixed part shows an Mem space for the device,
> +       and the Interrupt part shows the device interrupt.
> +_STA : the current status of the device, e.g. it's
> enabled/disabled/removed.
> +
> +By reading this example ASL code, we should know that there is a SD/MMC
> controller
> +on this platform, it's mem space base address is 0xFFA50000, length is
> 0x00000100,
> +and the irq for this device is 0x1b.
> +
> +In Chapter 2, we will use this piece of ASL code as an example to
> +show how to probe the SD/MMC controller via ACPI namespace.
> +
> +-----------------------------------------------------------------------------
> +2 Driver for a leaf device
> +-----------------------------------------------------------------------------
> +
> +2.1 Make a list of supported pnp ids.
> +
> +Use the string in _HID or _CID objects as the PnP ids so that the
> device can
> +be attached to the driver successfully.
> +
> +In this case,
> +struct pnp_device_id sdhci_pnp_ids[] = {
> +        { .id = "PNPXXXX",
> +          .driver_data = (unsigned long)&sdhci_mfd_pdata },
> +        { },
> +};
> +
> +2.2 Implement the .probe and .remove callback of PnP driver.
> +
> +If you're not clear about what should be done in the driver, you can
> consult
> +some similar driver, for example, drivers/mmc/host/sdhci-pci.c shows
> how
> +to probe a PCI SD/MMC controller, this helps us understand what should
> be done
> +in the .probe/.remove callback.
> +
> +By reading the sdhci-pci .probe function, we know that the .probe
> callback
> +needs to
> +a) alloc a sdhci host.
> +b) fill the sdhci host structure with necessary resources got from
> +   PCI configure space, including irq and mem space for the sdhci host.
> +c) register the sdhci host.
> +And then, driver/mmc/host/sdhci.c, the SDHCI interface driver will
> handle
> +everything for us.
> +
> +So, basically, we need to do the same work in sdhci_pnp_probe callback,
> +except that we need to get the information from ACPI namesapce instead.
> +
> +To get the resources in _CRS, we do not need Linux ACPICA APIs as PnP
> layer
> +has done this for us already.
> +
> +pnp_irq() returns the device irq, which equals the "Interrupt" part in
> _CRS method.
> +pnp_get_resource(, IORESOURCE_MEM, 0) returns the first Mem space base
> address
> +and length of this device, which equals the "Memory32Fixed" Part of the
> _CRS.
> +
> +the code below shows how to use the PnP APIs to get ACPI resources and
> +register a sdhci host in the .probe callback.
> +
> +static int __devinit
> +sdhci_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
> *dev_id)
> +{
> +...
> +	pnp_disable_dev(pdev);
> +	ret = pnp_activate_dev(pdev);
> +...
> +	iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
> +...
> +	host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pnp_dev));
> +...
> +	host->irq = pnp_irq(pdev, 0);
> +...
> +        if (!request_mem_region(iomem->start, resource_size(iomem),
> +                        mmc_hostname(host->mmc))) {
> +...
> +        host->ioaddr = ioremap_nocache(iomem->start,
> resource_size(iomem));
> +...
> +	ret = sdhci_add_host(host);
> +...
> +	pnp_set_drvdata(pdev, sdhci);
> +...
> +}
> +
> +Once the .probe callback is done, we just need to release the resources
> and
> +unregister the host in the .remove callback.
> +
> +static void sdhci_pnp_remove(struct pnp_dev * pdev)
> +{
> +	struct sdhci_pnp_dev *sdhci = pnp_get_drvdata(pdev);
> +	struct resources *iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
> +...
> +	sdhci_remove_host(sdhci->host, dead);
> +	sdhci_free_host(sdhci->host);
> +	iounmap(sdhci->host->ioaddr);
> +	release_mem_region(iomem->start, resource_size(iomem));
> +	pnp_set_drvdata(pdev, NULL);
> +	pnp_disable_dev(pdev);
> +}
> +
> +2.3 Fill in the pnp_driver structure
> +
> +Next step is to fill in the pnp_driver structure with PnP ids and
> +.probe/.remove callbacks finished in section 2.1 and 2.2
> +
> +static struct pnp_driver sdhci_pnp_driver = {
> +        .name =         DRIVER_NAME,
> +        .id_table =     sdhci_pnp_ids,
> +        .probe =        sdhci_pnp_probe,
> +        .remove =       __devexit_p(sdhci_pnp_remove),
> +};
> +
> +Note that .name and .id_table cannot be NULL.
> +
> +2.4 Register the PnP driver
> +
> +Now we can register this PnP driver to the driver model.
> +
> +static int __init sdhci_pnp_init(void)
> +{
> +	return pnp_register_driver(&sdhci_pnp_driver);
> +}
> +
> +module_init(sdhci_pnp_init);
> +
> +
> +-----------------------------------------------------------------------------
> +3 Driver for a master device on a non-self-enumerable bus
> +-----------------------------------------------------------------------------
> +In some cases, enumerating via ACPI brings new requirements in the
> driver.
> +For example, the driver for a master device on a non-self-enumerable
> bus is
> +responsible for enumerating the slave devices on this bus as well,
> which are
> +described as child devices of this master device in ACPI namespace.
> +
> +Taking SPI bus for example,
> +
> +-------------------------------------------------------------------
> +PNP/ACPI layer
> +
> +   spi-acpi driver
> +         |
> +         |-----------------|
> +         |                 |
> +         |                 |
> +         V                 V
> +   register itself    register its children
> +   as a master        as slave devices
> +   device                  |
> +         |                 |
> +---------|-----------------|---------------------------------------
> +         |                 |
> +         |                 |
> +         |                 |
> +         V                 V
> +     --------------      -----------
> +     |   SPI      |      |  SPI    |
> +     |   master   |      |  slave  |
> +     --------------      -----------
> +                           ^
> +                           |
> +                           |
> +                           V
> +                         -----------------------------
> +                         |  SPI slave driver driver  |
> +                         -----------------------------
> +SPI Bus layer
> +-------------------------------------------------------------------
> +
> +The figure above shows the components needed to make a SPI slave device
> work
> +a) an PNP/ACPI driver to probe the SPI master and its slaves.
> +b) a SPI slave device driver for the SPI slave device.
> +
> +[Case Study 2] SPI controller and its slave device
> +
> +This piece of ASL code shows the definition of a SPI controller and its
> slave device,
> +MAX3110, in ACPI namespace.
> +
> +Device (SPI1) {
> +	Name (_ADR, 0)
> +	Name (_HID, "PNPYYYY")
> +	Name (_CID, "PNPYYYY")
> +	Name (_UID, 1)
> +
> +	Method (_CRS, 0x0, NotSerialized) {
> +		Name (RBUF, ResourceTemplate ()
> +		{
> +			Memory32Fixed (ReadWrite, 0xff128400, 0x00000400)
> +			Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive, , , )
> {0x09}
> +		})
> +		Return (RBUF)
> +	}
> +
> +	Method (_STA, 0x0, NotSerialized) {
> +		Return(0xf)
> +	}
> +
> +	Device(MAX0)
> +	{
> +		Name(_HID, "PNPZZZZ")          // Max3110 serial port
> +		Name(_DDN, "Max3110 serial port")
> +		Method(_CRS, 0x0, NotSerialized)
> +		{
> +			// SpiSerial Bus Connection Descriptor
> +			Name(UBUF, ResourceTemplate () {
> +				SPISerialBus(
> +				1,                 // Device selection
> +				PolarityHigh,                       // Device selection polarity
> +				ThreeWireMode,                       // wiremode
> +				8,                   // databit len
> +				ControllerInitiated,                       // slave mode
> +				1000,                       // Connection speed
> +				ClockPolarityHigh,                       // Clock polarity
> +				ClockPhaseFirst,                     // clock phase
> +				"\\_SB.SPI1",           // ResourceSource: SPI bus controller name
> +				0,                      // ResourceSourceIndex
> +				ResourceConsumer,                       // Resource usage
> +				,                       // DescriptorName: creates name for offset
> of resource descriptor
> +				)                      // Vendor Data
> +				// OUT pin, BT_EN pin Core GPIO 74
> +				GpioIo(Exclusive, PullDefault, 0, 0, IoRestrictionOutputOnly, "\
> \_SB.GPIS", ) {0x4A}
> +			})
> +
> +			Return (UBUF)
> +		}
> +	}
> +}
> +
> +By reading the ASL code, we can see that
> +a) There is a SPI controller on this platform.
> +   with IRQ 0x09, and a 0x400 bytes Memory space started from
> 0xff128400.
> +b) a MAX3110 device is connect to a SPI controller.
> +   all the information required for probing a SPI slave device is
> described
> +   in the "SPISerailBus" part of the MAX0._CRS method.
> +
> +We will talk about how to probe these two devices in this chapter.
> +
> +3.1 Probe the master device
> +
> +Please follow the Chapter 2 to probe the SPI master device.
> +
> +static int __devinit
> +dw_spi_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
> *dev_id)
> +{
> +...
> +	dws->paddr = pnp_mem_start(pdev, 0);
> +	dws->iolen = pnp_mem_len(pdev, 0);
> +	dws->irq = pnp_irq(pdev, 0);
> +	dws->parent_dev = &pdev->dev;
> +	dws->bus_num = index++;
> +	dws->num_cs = 4;
> +	dws->regs = ioremap_nocache((unsigned long)dws->paddr,
> +				dws->iolen);
> +...
> +	ret = dw_spi_mid_init(dws);
> +...
> +	ret = dw_spi_add_host(dws);
> +...
> +}
> +
> +3.2 Walk ACPI namespace to probe all its child devices.
> +
> +As MAX3110 can not be enumerated automatically, we introduce
> +dw_spi_pnp_slaves_register() to find the MAX3110 device in ACPI
> namespace
> +
> +static int __devinit dw_spi_pnp_slaves_register(struct dw_spi_pnp*
> dwpnp)
> +{
> +	...
> +	struct acpi_device *adev;
> +	adev = dwpnp->pdev->data;
> +
> +	/*
> +	 * find spi child devices given in ACPI namespace, one lower level
> only
> +	 */
> +	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, adev->handle, 1,
> +				     spi_slave_register, NULL,
> +				     spi_slave_info, NULL);
> +	...
> +}
> +
> +3.3 Register its child devices as slave devices
> +
> +As spi_slave_register is invoked for each SPI1 child device,
> +we introduce spi_slave_fill_resourcetry and try to register
> +SPI slave devices in spi_slave_register.
> +
> +acpi_status __init spi_slave_register(acpi_handle spi_slave_handle, u32
> level,
> +				      void* data, void** return_value)
> +{
> +	...
> +	struct spi_board_info *spi_slave_info;
> +	...
> +	status = acpi_walk_resources(spi_slave_handle, METHOD_NAME__CRS,
> +				     spi_slave_fill_resource, data);
> +	...
> +	/* register SPI slave device */
> +	ret = spi_register_board_info(spi_slave_info, 1);
> +	...
> +}
> +
> +acpi_status __devinit spi_slave_fill_resource(struct acpi_resource
> *resource, void* data)
> +{
> +	struct spi_board_info *spi_slave_info;
> +	struct acpi_resource_spi_serialbus *spi_resource;
> +	...
> +	  	spi_resource = &resource->data.spi_serial_bus;
> +	  	spi_slave_info->chip_select = spi_resource->device_selection;
> +	  	spi_slave_info->max_speed_hz = spi_resource->connection_speed;
> +	  	spi_slave_info->mode = (spi_resource->clock_phase ? SPI_CPHA : 0) |
> +	  		(spi_resource->clock_polarity ? SPI_CPOL : 0) |
> +	  		(spi_resource->device_polarity ? SPI_CS_HIGH : 0) |
> +	  		(spi_resource->wire_mode ? SPI_3WIRE : 0);
> +	...
> +}
> +
> +3.4 Write the slave device driver
> +
> +After 3.3 is done, the MAX3110 device is an slave device in the SPI
> bus,
> +but to make it work properly, we still need a SPI slave device driver.
> +
> +Note that this is a general SPI drivers independent of ACPI.
> +
> +We will not go into details of the slave device driver here as
> +this piece of code is bus/device specific.
> +
> +-----------------------------------------------------------------------------
> +4 Misc
> +-----------------------------------------------------------------------------
> +
> +4.1 Note
> +
> +As ACPI 5.0 is still in heavily developing, if you are unable to find
> out all the
> +required information for probing a device in ACPI namespace, it is
> possible
> +that the ASL code is not well written.
> +Please contact Zhang Rui <rui.zhang@intel.com> with the acpidump output
> of your
> +platform attached if you suspect it's an BIOS problem.
> +
> +4.2 Some important ACPICA APIs for device driver implementation:
> +
> +-- acpi_status
> +   acpi_walk_namespace(acpi_object_type type,
> +		       acpi_handle start_object,
> +		       u32 max_depth,
> +		       acpi_walk_callback pre_order_visit,
> +		       acpi_walk_callback post_order_visit,
> +		       void *context, void **return_value);
> +Traverse ACPI namespace subtree rooted at start_object, go down
> max_depth level
> +at most. Call pre_order_visit when the proper node with type is found
> the first
> +time, call post_order_visit is the node is previously visited. Context
> and
> +return_value is passed down during the traverse.
> +
> +And the prototype of acpi_walk_callback:
> +typedef
> +acpi_status(*acpi_walk_callback) (acpi_handle object,
> +				  u32 nesting_level,
> +				  void *context, void **return_value);
> +
> +-- acpi_status
> +   acpi_get_handle(acpi_handle parent,
> +   		   acpi_string pathname, acpi_handle * ret_handle);
> +Try to get handle with specified pathname under node parent. Usually
> used to
> +check whether a particular node is available or not.
> +
> +-- acpi_status
> +   acpi_get_object_info(acpi_handle object,
> +		        struct acpi_device_info **return_buffer);
> +Get acpi_device_info from object handle. Useful for retrieving ACPI
> object
> +name, type, and status etc.
> +
> +-- acpi_status
> +   acpi_walk_resources(acpi_handle device,
> +		       char *name,
> +	    	       acpi_walk_resource_callback user_function, void *context);
> +Traverse resource node specified by name(e.g. METHOD_NAME__CRS) in ACPI
> +namespace subtree rooted at device. Call user_function for each entry
> in
> +acpi_resource list. The list may containe acpi_resource entries with
> various
> +types. So it is important to handle the interested resource type
> properly.
> +The acpi_resource with ACPI_RESOURCE_TYPE_END_TAG indicates
> end-of-list.
> +
> +And the prototype of acpi_walk_resource_callback:
> +typedef
> +acpi_status(*acpi_walk_resource_callback) (struct acpi_resource *
> resource,
> +					   void *context);
> +
> +More ACPICA external interfaces available in include/acpi/acpixf.h


--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Benjamin Tissoires July 5, 2012, 8:44 a.m. UTC | #2
Hi,

Many thanks for these information. It seems like I was on the right
track, but I didn't saw the hidden part of the iceberg.
I've already written the i2c slave part (and the acpi handling to get
the HID register by using the DSM should work), but I need now the
whole ACPI pnp drivers...

But without a real ACPI 5.0 mainboard, I think it will be quite
difficult to implement and debug this ACPI stuff.

Cheers,
Benjamin

On Thu, Jul 5, 2012 at 9:20 AM, Zhang Rui <rui.zhang@intel.com> wrote:
> Hah, seems I forgot to reply to Benjamin.
>
> On ?, 2012-07-05 at 15:01 +0800, Zhang Rui wrote:
>> > -------- Original Message --------
>> > Subject: Hid over I2C and ACPI interaction
>> > Date: Wed, 4 Jul 2012 15:46:35 +0200
>> > From: Benjamin Tissoires <benjamin.tissoires@gmail.com>
>> > To: Jean Delvare <khali@linux-fr.org>, Ben Dooks <ben-linux@fluff.org>, Wolfram
>> > Sang <w.sang@pengutronix.de>, Len Brown <lenb@kernel.org>,
>> > <linux-acpi@vger.kernel.org>, <linux-i2c@vger.kernel.org>,
>> > <linux-kernel@vger.kernel.org>
>> > CC: Jiri Kosina <jkosina@suse.cz>, Stéphane Chatty <chatty@enac.fr>, JJ Ding
>> > <jj_ding@emc.com.tw>
>> >
>> > Hi Guys,
>> >
>> > I'm the co-author and the maintainer of the hid-multitouch driver. To
>> > support even more devices, I started the implementation of the HID
>> > over I2C protocol specification which is introduced by Win8. I'm quite
>> > comfortable with the hid and the I2C part, but I'm blocked with the
>> > interaction with the ACPI for the pnp part.
>> >
>> > I wanted to have your advice/help on this problem. I've add in the
>> > recipients list the maintainers of i2c and ACPI, sorry for the noise
>> > if you don't feel concerned about this.
>> >
>> > So, let's go deeper in the problem ;-)
>> > Microsoft's spec asks the OEM to fill the ACPI DSDT to provide the
>> > following scope in the ASL layout:
>> >
>> > >>>>>>>>> begin of ASL
>> > Scope (\_SB) {
>> > //--------------------
>> > //  General Purpose I/O, ports 0...127
>> > //--------------------
>> >
>> > Device(HIDI2C_DEVICE1) {
>> >      Name(_ADR,0)
>> >      Name (_HID, "MSFT1234”)
>> >      Name (_CID, "PNP0C50")
>> >      Name (_UID, 3)
>> >
>> >      Method(_CRS, 0x0, NotSerialized)
>> >      {
>> >          Name (RBUF, ResourceTemplate ()
>> >          {
>> >          // Address 0x07 on I2C-X (OEM selects this address)
>> >         //IHV SPECIFIC I2C3 = I2C Controller; TGD0 = GPIO Controller;
>> >          I2CSerialBus (0x07, ControllerInitiated,
>> > 100000,AddressingMode7Bit, "\\_SB.I2C3",,,,)
>> >          GpioInt(Level, ActiveLow, Exclusive, PullUp, 0, "\\_SB. TGD0",
>> > 0 , ResourceConsumer, , ) {40}
>> >          })
>> >       Return(RBUF)
>> >       }
>> >
>> >       Method(_DSM, 0x4, NotSerialized)
>> >       {
>> >          // BreakPoint
>> >          Store ("Method _DSM begin", Debug)
>> >
>> >          // DSM UUID
>> >          switch(ToBuffer(Arg0))
>> >          {
>> >              // ACPI DSM UUID for HIDI2C
>> >              case(ToUUID("3CDFF6F7-4267-4555-AD05-B30A3D8938DE"))
>> >              {
>> >                   // DSM function which returns the HID Descriptor
>> > Address (skipped)
>> >              }
>> >
>> >              default
>> >              {
>> >                  // No other GUIDs supported
>> >                  Return(Buffer(One) { 0x00 })
>> >              }
>> >          }
>> >      }
>> > }
>> > <<<<<<<<< end of ASL
>> >
>> yep, this is an ACPI enumerated I2C controller.
>>
>> > Summary:
>> > - a HID over I2C device has to present the Compatibility ID "PNP0C50"
>> > - in the _CRS block, the address, the adapter and the gpioInt are
>> > defined (or referenced)
>> > - it presents a Device Specific Method (_DSM) which returns the HID
>> > Descriptor register address. This register is our entry point for
>> > retrieving the information about our hid device (so it's mandatory to
>> > obtain it).
>> >
>> > Where am I:
>> > - I've written a first layer on top of i2c that retrieves the hid
>> > register (currently the address 0x0001 is hardcoded), then get the
>> > report desccriptors and the input events, and forward all this stuff
>> > to the hid layer.
>> > - It's working with a custom emulated HID over i2c touchpad, while
>> > waiting for the one a manufacturer should send to me.
>> > - The detection and the addition to the adapter is done by adding the
>> > address in the lists and the name through the i2c "->detect" callback
>> > (which is not very good, because I don't have the interrupt line
>> > there).
>> > - I've written a first acpi implementation that rely on the
>> > DEVICE_ACPI_HANDLE macro to get the ACPI handle of the device (if
>> > available).
>> > - I'm not able to do some tests with the ACPI, as I don't know how to
>> > implement this DSDT on my computer (I'm missing the I2C part), and the
>> > manufacturer returned the mainboard with the right DSDT to the OEM.
>> >
>> > My questions:
>> > - will the current acpi implementation handle I2C devices?
>>
>> you still need to write your own device driver for the device.
>>
>> > - it seems to me that the .archdata field is left blank during the i2c
>> > device initialization in all paths I've seen. Is that true?
>> > - who puts the name int the struct i2c_board_info? (for hot-plugged
>> > i2c devices).
>> >
>> > - finally, what is the best way of handling ACPI for those I2C devices:
>> >    1) everything is fine, I should have the ACPI handle in .archdata.
>> >    2) someone has to implement the handling of I2C in the pnpACPI layer
>> > (by adding I2CSerialBus handling and creating there the i2c slave).
>> >    3) I should create an acpi driver which handles "PNP0C50" and which
>> > creates the i2c slaves.
>> >
>> exactly.
>>
>> As this I2C controller uses the GPIO interrupt, we need an ACPI GPIO
>> controller driver for interrupts first.
>> I already have such a patch in hand, but have not release it for some
>> reason.
>> Second, you need to write your own PNP I2C controller driver, to
>> enumerate the I2C controller via ACPI, AND enumerate the I2C slave
>> devices under this controller to I2C bus. I also have a similar driver
>> for SPI controller and SD/MMC controller.
>> Third, you need a I2C slave device driver to handle the I2C slave device
>> in I2C bus.
>>
>> here is a BKM I wrote, hope it helps.
>>
>> And also any comments are welcome. :)
>>
>> From 0a0fa4ff7b4b06c6560de94a78b15c6adfd86e34 Mon Sep 17 00:00:00 2001
>> From: Zhang Rui <rui.zhang@intel.com>
>> Date: Mon, 26 Dec 2011 10:42:04 +0800
>>
>>  As many SoC IP blocks are not hardware self-enumerable, the
>>  firmware, aka, ACPI tables, is responsible for
>>  enumerating/reserving/assigning system resources to these
>>  devices. This tutorial talks about how to enumerate these
>>  devices via ACPI namespace.
>>
>> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>> ---
>>  Documentation/acpi/acpi-device-probing.txt |  466
>> ++++++++++++++++++++++++++++
>>  1 file changed, 466 insertions(+)
>>  create mode 100644 Documentation/acpi/acpi-device-probing.txt
>>
>> diff --git a/Documentation/acpi/acpi-device-probing.txt
>> b/Documentation/acpi/acpi-device-probing.txt
>> new file mode 100644
>> index 0000000..82efbf3
>> --- /dev/null
>> +++ b/Documentation/acpi/acpi-device-probing.txt
>> @@ -0,0 +1,466 @@
>> +
>> +HOWTO enumerate devices via ACPI
>> +
>> +Copyright (c) 2011-2012 Intel Corporation
>> +
>> +Contrast to hardware self-enumerable devices(e.g. USB, PCI) on PC
>> platform,
>> +many SoC IP blocks can not be self enumerated.
>> +We used to introduce platform specific code for these devices.
>> +But now, with ACPI 5.0, there is no requirement for the hardware to be
>> +self-discoverable, enumerable or re-locatable, as the firmware is
>> responsible
>> +for enumerating/reserving/assigning system resources (such as address
>> ranges or
>> +interrupts) to the device.
>> +
>> +This document will show how to enumerate and configure a device via
>> ACPI.
>> +If you want to get more details about why and when we need this,
>> +please refer to ACPI spec 5.0 and
>> +Intel Architecture Platform Compatibility Definition.
>> +
>> +Note that although these are ACPI devices, we prefer to use PnP drivers
>> for them,
>> +this is because:
>> +1. all the non-ACPI-predefined Devices are exported as PnP devices as
>> well
>> +2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
>> work
>> +   for the device driver, e.g. getting & parsing ACPI resources.
>> +
>> +=============================================================================
>> +1. Understand device definition in ACPI namespace
>> +   [Case study 1] SD/MMC controller
>> +2. Driver for a leaf device
>> +   2.1 Make a list of supported PnP ids
>> +   2.2 Implement .probe/.remove callbacks for the PnP driver
>> +   2.3 Fill in the pnp_driver structure
>> +   2.4 Register the PnP driver
>> +3. Driver for a master device on a non-self-enumerable bus
>> +   [Case Study 2] SPI controller and its slave device
>> +   3.1 Probe the master device
>> +   3.2 Walk ACPI namesapce to get the child devices of the master
>> device
>> +   3.3 Register these child devices as slave devices
>> +   3.4 Write slave device driver
>> +4. Misc
>> +=============================================================================
>> +
>> +-----------------------------------------------------------------------------
>> +1. Understand device definition in ACPI namespace
>> +-----------------------------------------------------------------------------
>> +
>> +To enumerate a device in ACPI namespace, we need to find out and
>> understand
>> +HOW the device is defined in ACPI namespace first.
>> +
>> +[Case study 1 ] SD/MMC Controller
>> +
>> +Here is an ASL example code for SD/MMC controller definition in ACPI
>> namespace.
>> +
>> +        Device (EMMC)
>> +        {
>> +            Name (_ADR, Zero)
>> +            /* I use PNPXXXX, an arbitrary string, here, as PnP id is
>> device specific */
>> +            Name (_HID, "PNPXXXX")
>> +            Name (_CID, "PNPXXXX")
>> +            Name (_UID, 4)
>> +
>> +            Method (_CRS, 0, NotSerialized)
>> +            {
>> +                Name (RBUF, ResourceTemplate ()
>> +                {
>> +                    Memory32Fixed (ReadWrite,
>> +                        0xFFA50000,         // Address Base
>> +                        0x00000100,         // Address Length
>> +                        )
>> +                    Interrupt (ResourceConsumer, Level, ActiveLow,
>> Exclusive, ,, )
>> +                    {
>> +                        0x0000001b,
>> +                    }
>> +                })
>> +                Return (RBUF)
>> +            }
>> +
>> +            Method (_STA, 0, NotSerialized)
>> +            {
>> +                Return (0x0F)
>> +            }
>> +        }
>> +
>> +_ADR : the address of this device on its parent bus. Useless in this
>> case.
>> +_HID : the PnP id for this device.
>> +_CID : the compatible PnP id. use this as the PnP id if _HID doesn't
>> exist.
>> +_CRS : the system resources currently allocated to this device.
>> +       the Memory32Fixed part shows an Mem space for the device,
>> +       and the Interrupt part shows the device interrupt.
>> +_STA : the current status of the device, e.g. it's
>> enabled/disabled/removed.
>> +
>> +By reading this example ASL code, we should know that there is a SD/MMC
>> controller
>> +on this platform, it's mem space base address is 0xFFA50000, length is
>> 0x00000100,
>> +and the irq for this device is 0x1b.
>> +
>> +In Chapter 2, we will use this piece of ASL code as an example to
>> +show how to probe the SD/MMC controller via ACPI namespace.
>> +
>> +-----------------------------------------------------------------------------
>> +2 Driver for a leaf device
>> +-----------------------------------------------------------------------------
>> +
>> +2.1 Make a list of supported pnp ids.
>> +
>> +Use the string in _HID or _CID objects as the PnP ids so that the
>> device can
>> +be attached to the driver successfully.
>> +
>> +In this case,
>> +struct pnp_device_id sdhci_pnp_ids[] = {
>> +        { .id = "PNPXXXX",
>> +          .driver_data = (unsigned long)&sdhci_mfd_pdata },
>> +        { },
>> +};
>> +
>> +2.2 Implement the .probe and .remove callback of PnP driver.
>> +
>> +If you're not clear about what should be done in the driver, you can
>> consult
>> +some similar driver, for example, drivers/mmc/host/sdhci-pci.c shows
>> how
>> +to probe a PCI SD/MMC controller, this helps us understand what should
>> be done
>> +in the .probe/.remove callback.
>> +
>> +By reading the sdhci-pci .probe function, we know that the .probe
>> callback
>> +needs to
>> +a) alloc a sdhci host.
>> +b) fill the sdhci host structure with necessary resources got from
>> +   PCI configure space, including irq and mem space for the sdhci host.
>> +c) register the sdhci host.
>> +And then, driver/mmc/host/sdhci.c, the SDHCI interface driver will
>> handle
>> +everything for us.
>> +
>> +So, basically, we need to do the same work in sdhci_pnp_probe callback,
>> +except that we need to get the information from ACPI namesapce instead.
>> +
>> +To get the resources in _CRS, we do not need Linux ACPICA APIs as PnP
>> layer
>> +has done this for us already.
>> +
>> +pnp_irq() returns the device irq, which equals the "Interrupt" part in
>> _CRS method.
>> +pnp_get_resource(, IORESOURCE_MEM, 0) returns the first Mem space base
>> address
>> +and length of this device, which equals the "Memory32Fixed" Part of the
>> _CRS.
>> +
>> +the code below shows how to use the PnP APIs to get ACPI resources and
>> +register a sdhci host in the .probe callback.
>> +
>> +static int __devinit
>> +sdhci_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
>> *dev_id)
>> +{
>> +...
>> +     pnp_disable_dev(pdev);
>> +     ret = pnp_activate_dev(pdev);
>> +...
>> +     iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
>> +...
>> +     host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pnp_dev));
>> +...
>> +     host->irq = pnp_irq(pdev, 0);
>> +...
>> +        if (!request_mem_region(iomem->start, resource_size(iomem),
>> +                        mmc_hostname(host->mmc))) {
>> +...
>> +        host->ioaddr = ioremap_nocache(iomem->start,
>> resource_size(iomem));
>> +...
>> +     ret = sdhci_add_host(host);
>> +...
>> +     pnp_set_drvdata(pdev, sdhci);
>> +...
>> +}
>> +
>> +Once the .probe callback is done, we just need to release the resources
>> and
>> +unregister the host in the .remove callback.
>> +
>> +static void sdhci_pnp_remove(struct pnp_dev * pdev)
>> +{
>> +     struct sdhci_pnp_dev *sdhci = pnp_get_drvdata(pdev);
>> +     struct resources *iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
>> +...
>> +     sdhci_remove_host(sdhci->host, dead);
>> +     sdhci_free_host(sdhci->host);
>> +     iounmap(sdhci->host->ioaddr);
>> +     release_mem_region(iomem->start, resource_size(iomem));
>> +     pnp_set_drvdata(pdev, NULL);
>> +     pnp_disable_dev(pdev);
>> +}
>> +
>> +2.3 Fill in the pnp_driver structure
>> +
>> +Next step is to fill in the pnp_driver structure with PnP ids and
>> +.probe/.remove callbacks finished in section 2.1 and 2.2
>> +
>> +static struct pnp_driver sdhci_pnp_driver = {
>> +        .name =         DRIVER_NAME,
>> +        .id_table =     sdhci_pnp_ids,
>> +        .probe =        sdhci_pnp_probe,
>> +        .remove =       __devexit_p(sdhci_pnp_remove),
>> +};
>> +
>> +Note that .name and .id_table cannot be NULL.
>> +
>> +2.4 Register the PnP driver
>> +
>> +Now we can register this PnP driver to the driver model.
>> +
>> +static int __init sdhci_pnp_init(void)
>> +{
>> +     return pnp_register_driver(&sdhci_pnp_driver);
>> +}
>> +
>> +module_init(sdhci_pnp_init);
>> +
>> +
>> +-----------------------------------------------------------------------------
>> +3 Driver for a master device on a non-self-enumerable bus
>> +-----------------------------------------------------------------------------
>> +In some cases, enumerating via ACPI brings new requirements in the
>> driver.
>> +For example, the driver for a master device on a non-self-enumerable
>> bus is
>> +responsible for enumerating the slave devices on this bus as well,
>> which are
>> +described as child devices of this master device in ACPI namespace.
>> +
>> +Taking SPI bus for example,
>> +
>> +-------------------------------------------------------------------
>> +PNP/ACPI layer
>> +
>> +   spi-acpi driver
>> +         |
>> +         |-----------------|
>> +         |                 |
>> +         |                 |
>> +         V                 V
>> +   register itself    register its children
>> +   as a master        as slave devices
>> +   device                  |
>> +         |                 |
>> +---------|-----------------|---------------------------------------
>> +         |                 |
>> +         |                 |
>> +         |                 |
>> +         V                 V
>> +     --------------      -----------
>> +     |   SPI      |      |  SPI    |
>> +     |   master   |      |  slave  |
>> +     --------------      -----------
>> +                           ^
>> +                           |
>> +                           |
>> +                           V
>> +                         -----------------------------
>> +                         |  SPI slave driver driver  |
>> +                         -----------------------------
>> +SPI Bus layer
>> +-------------------------------------------------------------------
>> +
>> +The figure above shows the components needed to make a SPI slave device
>> work
>> +a) an PNP/ACPI driver to probe the SPI master and its slaves.
>> +b) a SPI slave device driver for the SPI slave device.
>> +
>> +[Case Study 2] SPI controller and its slave device
>> +
>> +This piece of ASL code shows the definition of a SPI controller and its
>> slave device,
>> +MAX3110, in ACPI namespace.
>> +
>> +Device (SPI1) {
>> +     Name (_ADR, 0)
>> +     Name (_HID, "PNPYYYY")
>> +     Name (_CID, "PNPYYYY")
>> +     Name (_UID, 1)
>> +
>> +     Method (_CRS, 0x0, NotSerialized) {
>> +             Name (RBUF, ResourceTemplate ()
>> +             {
>> +                     Memory32Fixed (ReadWrite, 0xff128400, 0x00000400)
>> +                     Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive, , , )
>> {0x09}
>> +             })
>> +             Return (RBUF)
>> +     }
>> +
>> +     Method (_STA, 0x0, NotSerialized) {
>> +             Return(0xf)
>> +     }
>> +
>> +     Device(MAX0)
>> +     {
>> +             Name(_HID, "PNPZZZZ")          // Max3110 serial port
>> +             Name(_DDN, "Max3110 serial port")
>> +             Method(_CRS, 0x0, NotSerialized)
>> +             {
>> +                     // SpiSerial Bus Connection Descriptor
>> +                     Name(UBUF, ResourceTemplate () {
>> +                             SPISerialBus(
>> +                             1,                 // Device selection
>> +                             PolarityHigh,                       // Device selection polarity
>> +                             ThreeWireMode,                       // wiremode
>> +                             8,                   // databit len
>> +                             ControllerInitiated,                       // slave mode
>> +                             1000,                       // Connection speed
>> +                             ClockPolarityHigh,                       // Clock polarity
>> +                             ClockPhaseFirst,                     // clock phase
>> +                             "\\_SB.SPI1",           // ResourceSource: SPI bus controller name
>> +                             0,                      // ResourceSourceIndex
>> +                             ResourceConsumer,                       // Resource usage
>> +                             ,                       // DescriptorName: creates name for offset
>> of resource descriptor
>> +                             )                      // Vendor Data
>> +                             // OUT pin, BT_EN pin Core GPIO 74
>> +                             GpioIo(Exclusive, PullDefault, 0, 0, IoRestrictionOutputOnly, "\
>> \_SB.GPIS", ) {0x4A}
>> +                     })
>> +
>> +                     Return (UBUF)
>> +             }
>> +     }
>> +}
>> +
>> +By reading the ASL code, we can see that
>> +a) There is a SPI controller on this platform.
>> +   with IRQ 0x09, and a 0x400 bytes Memory space started from
>> 0xff128400.
>> +b) a MAX3110 device is connect to a SPI controller.
>> +   all the information required for probing a SPI slave device is
>> described
>> +   in the "SPISerailBus" part of the MAX0._CRS method.
>> +
>> +We will talk about how to probe these two devices in this chapter.
>> +
>> +3.1 Probe the master device
>> +
>> +Please follow the Chapter 2 to probe the SPI master device.
>> +
>> +static int __devinit
>> +dw_spi_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
>> *dev_id)
>> +{
>> +...
>> +     dws->paddr = pnp_mem_start(pdev, 0);
>> +     dws->iolen = pnp_mem_len(pdev, 0);
>> +     dws->irq = pnp_irq(pdev, 0);
>> +     dws->parent_dev = &pdev->dev;
>> +     dws->bus_num = index++;
>> +     dws->num_cs = 4;
>> +     dws->regs = ioremap_nocache((unsigned long)dws->paddr,
>> +                             dws->iolen);
>> +...
>> +     ret = dw_spi_mid_init(dws);
>> +...
>> +     ret = dw_spi_add_host(dws);
>> +...
>> +}
>> +
>> +3.2 Walk ACPI namespace to probe all its child devices.
>> +
>> +As MAX3110 can not be enumerated automatically, we introduce
>> +dw_spi_pnp_slaves_register() to find the MAX3110 device in ACPI
>> namespace
>> +
>> +static int __devinit dw_spi_pnp_slaves_register(struct dw_spi_pnp*
>> dwpnp)
>> +{
>> +     ...
>> +     struct acpi_device *adev;
>> +     adev = dwpnp->pdev->data;
>> +
>> +     /*
>> +      * find spi child devices given in ACPI namespace, one lower level
>> only
>> +      */
>> +     status = acpi_walk_namespace(ACPI_TYPE_DEVICE, adev->handle, 1,
>> +                                  spi_slave_register, NULL,
>> +                                  spi_slave_info, NULL);
>> +     ...
>> +}
>> +
>> +3.3 Register its child devices as slave devices
>> +
>> +As spi_slave_register is invoked for each SPI1 child device,
>> +we introduce spi_slave_fill_resourcetry and try to register
>> +SPI slave devices in spi_slave_register.
>> +
>> +acpi_status __init spi_slave_register(acpi_handle spi_slave_handle, u32
>> level,
>> +                                   void* data, void** return_value)
>> +{
>> +     ...
>> +     struct spi_board_info *spi_slave_info;
>> +     ...
>> +     status = acpi_walk_resources(spi_slave_handle, METHOD_NAME__CRS,
>> +                                  spi_slave_fill_resource, data);
>> +     ...
>> +     /* register SPI slave device */
>> +     ret = spi_register_board_info(spi_slave_info, 1);
>> +     ...
>> +}
>> +
>> +acpi_status __devinit spi_slave_fill_resource(struct acpi_resource
>> *resource, void* data)
>> +{
>> +     struct spi_board_info *spi_slave_info;
>> +     struct acpi_resource_spi_serialbus *spi_resource;
>> +     ...
>> +             spi_resource = &resource->data.spi_serial_bus;
>> +             spi_slave_info->chip_select = spi_resource->device_selection;
>> +             spi_slave_info->max_speed_hz = spi_resource->connection_speed;
>> +             spi_slave_info->mode = (spi_resource->clock_phase ? SPI_CPHA : 0) |
>> +                     (spi_resource->clock_polarity ? SPI_CPOL : 0) |
>> +                     (spi_resource->device_polarity ? SPI_CS_HIGH : 0) |
>> +                     (spi_resource->wire_mode ? SPI_3WIRE : 0);
>> +     ...
>> +}
>> +
>> +3.4 Write the slave device driver
>> +
>> +After 3.3 is done, the MAX3110 device is an slave device in the SPI
>> bus,
>> +but to make it work properly, we still need a SPI slave device driver.
>> +
>> +Note that this is a general SPI drivers independent of ACPI.
>> +
>> +We will not go into details of the slave device driver here as
>> +this piece of code is bus/device specific.
>> +
>> +-----------------------------------------------------------------------------
>> +4 Misc
>> +-----------------------------------------------------------------------------
>> +
>> +4.1 Note
>> +
>> +As ACPI 5.0 is still in heavily developing, if you are unable to find
>> out all the
>> +required information for probing a device in ACPI namespace, it is
>> possible
>> +that the ASL code is not well written.
>> +Please contact Zhang Rui <rui.zhang@intel.com> with the acpidump output
>> of your
>> +platform attached if you suspect it's an BIOS problem.
>> +
>> +4.2 Some important ACPICA APIs for device driver implementation:
>> +
>> +-- acpi_status
>> +   acpi_walk_namespace(acpi_object_type type,
>> +                    acpi_handle start_object,
>> +                    u32 max_depth,
>> +                    acpi_walk_callback pre_order_visit,
>> +                    acpi_walk_callback post_order_visit,
>> +                    void *context, void **return_value);
>> +Traverse ACPI namespace subtree rooted at start_object, go down
>> max_depth level
>> +at most. Call pre_order_visit when the proper node with type is found
>> the first
>> +time, call post_order_visit is the node is previously visited. Context
>> and
>> +return_value is passed down during the traverse.
>> +
>> +And the prototype of acpi_walk_callback:
>> +typedef
>> +acpi_status(*acpi_walk_callback) (acpi_handle object,
>> +                               u32 nesting_level,
>> +                               void *context, void **return_value);
>> +
>> +-- acpi_status
>> +   acpi_get_handle(acpi_handle parent,
>> +                acpi_string pathname, acpi_handle * ret_handle);
>> +Try to get handle with specified pathname under node parent. Usually
>> used to
>> +check whether a particular node is available or not.
>> +
>> +-- acpi_status
>> +   acpi_get_object_info(acpi_handle object,
>> +                     struct acpi_device_info **return_buffer);
>> +Get acpi_device_info from object handle. Useful for retrieving ACPI
>> object
>> +name, type, and status etc.
>> +
>> +-- acpi_status
>> +   acpi_walk_resources(acpi_handle device,
>> +                    char *name,
>> +                    acpi_walk_resource_callback user_function, void *context);
>> +Traverse resource node specified by name(e.g. METHOD_NAME__CRS) in ACPI
>> +namespace subtree rooted at device. Call user_function for each entry
>> in
>> +acpi_resource list. The list may containe acpi_resource entries with
>> various
>> +types. So it is important to handle the interested resource type
>> properly.
>> +The acpi_resource with ACPI_RESOURCE_TYPE_END_TAG indicates
>> end-of-list.
>> +
>> +And the prototype of acpi_walk_resource_callback:
>> +typedef
>> +acpi_status(*acpi_walk_resource_callback) (struct acpi_resource *
>> resource,
>> +                                        void *context);
>> +
>> +More ACPICA external interfaces available in include/acpi/acpixf.h
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg July 6, 2012, 5:52 a.m. UTC | #3
On Thu, Jul 05, 2012 at 03:01:57PM +0800, Zhang Rui wrote:
> +Note that although these are ACPI devices, we prefer to use PnP drivers
> for them,
> +this is because:
> +1. all the non-ACPI-predefined Devices are exported as PnP devices as
> well
> +2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
> work
> +   for the device driver, e.g. getting & parsing ACPI resources.

(Nice BKM, thanks for sharing)

I have few questions about using PnP drivers instead of pure ACPI drivers.

ACPI 5.0 defined some new resources, for example "Fixed DMA descriptor"
that has information about the request line + channel for the device to
use. Hovewer, PnP drivers pass resources as 'struct resource', which
basically only has start and end - how do you represent all this new stuff
using 'struct resource'?

Or should we use acpi_walk_resources() where 'struct resource' is not
suitable?
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zhang, Rui July 9, 2012, 12:41 a.m. UTC | #4
On ?, 2012-07-05 at 10:44 +0200, Benjamin Tissoires wrote:
> Hi,
> 
> Many thanks for these information. It seems like I was on the right
> track, but I didn't saw the hidden part of the iceberg.

yep.

> I've already written the i2c slave part (and the acpi handling to get
> the HID register by using the DSM should work), but I need now the
> whole ACPI pnp drivers...
> 
you need the ACPI/PNP I2C controller driver.

> But without a real ACPI 5.0 mainboard, I think it will be quite
> difficult to implement and debug this ACPI stuff.
> 
yes, that's the problem I have. I can not send out the code based on
some example ASL code. :)

thanks,
rui

> Cheers,
> Benjamin
> 
> On Thu, Jul 5, 2012 at 9:20 AM, Zhang Rui <rui.zhang@intel.com> wrote:
> > Hah, seems I forgot to reply to Benjamin.
> >
> > On ?, 2012-07-05 at 15:01 +0800, Zhang Rui wrote:
> >> > -------- Original Message --------
> >> > Subject: Hid over I2C and ACPI interaction
> >> > Date: Wed, 4 Jul 2012 15:46:35 +0200
> >> > From: Benjamin Tissoires <benjamin.tissoires@gmail.com>
> >> > To: Jean Delvare <khali@linux-fr.org>, Ben Dooks <ben-linux@fluff.org>, Wolfram
> >> > Sang <w.sang@pengutronix.de>, Len Brown <lenb@kernel.org>,
> >> > <linux-acpi@vger.kernel.org>, <linux-i2c@vger.kernel.org>,
> >> > <linux-kernel@vger.kernel.org>
> >> > CC: Jiri Kosina <jkosina@suse.cz>, Stéphane Chatty <chatty@enac.fr>, JJ Ding
> >> > <jj_ding@emc.com.tw>
> >> >
> >> > Hi Guys,
> >> >
> >> > I'm the co-author and the maintainer of the hid-multitouch driver. To
> >> > support even more devices, I started the implementation of the HID
> >> > over I2C protocol specification which is introduced by Win8. I'm quite
> >> > comfortable with the hid and the I2C part, but I'm blocked with the
> >> > interaction with the ACPI for the pnp part.
> >> >
> >> > I wanted to have your advice/help on this problem. I've add in the
> >> > recipients list the maintainers of i2c and ACPI, sorry for the noise
> >> > if you don't feel concerned about this.
> >> >
> >> > So, let's go deeper in the problem ;-)
> >> > Microsoft's spec asks the OEM to fill the ACPI DSDT to provide the
> >> > following scope in the ASL layout:
> >> >
> >> > >>>>>>>>> begin of ASL
> >> > Scope (\_SB) {
> >> > //--------------------
> >> > //  General Purpose I/O, ports 0...127
> >> > //--------------------
> >> >
> >> > Device(HIDI2C_DEVICE1) {
> >> >      Name(_ADR,0)
> >> >      Name (_HID, "MSFT1234”)
> >> >      Name (_CID, "PNP0C50")
> >> >      Name (_UID, 3)
> >> >
> >> >      Method(_CRS, 0x0, NotSerialized)
> >> >      {
> >> >          Name (RBUF, ResourceTemplate ()
> >> >          {
> >> >          // Address 0x07 on I2C-X (OEM selects this address)
> >> >         //IHV SPECIFIC I2C3 = I2C Controller; TGD0 = GPIO Controller;
> >> >          I2CSerialBus (0x07, ControllerInitiated,
> >> > 100000,AddressingMode7Bit, "\\_SB.I2C3",,,,)
> >> >          GpioInt(Level, ActiveLow, Exclusive, PullUp, 0, "\\_SB. TGD0",
> >> > 0 , ResourceConsumer, , ) {40}
> >> >          })
> >> >       Return(RBUF)
> >> >       }
> >> >
> >> >       Method(_DSM, 0x4, NotSerialized)
> >> >       {
> >> >          // BreakPoint
> >> >          Store ("Method _DSM begin", Debug)
> >> >
> >> >          // DSM UUID
> >> >          switch(ToBuffer(Arg0))
> >> >          {
> >> >              // ACPI DSM UUID for HIDI2C
> >> >              case(ToUUID("3CDFF6F7-4267-4555-AD05-B30A3D8938DE"))
> >> >              {
> >> >                   // DSM function which returns the HID Descriptor
> >> > Address (skipped)
> >> >              }
> >> >
> >> >              default
> >> >              {
> >> >                  // No other GUIDs supported
> >> >                  Return(Buffer(One) { 0x00 })
> >> >              }
> >> >          }
> >> >      }
> >> > }
> >> > <<<<<<<<< end of ASL
> >> >
> >> yep, this is an ACPI enumerated I2C controller.
> >>
> >> > Summary:
> >> > - a HID over I2C device has to present the Compatibility ID "PNP0C50"
> >> > - in the _CRS block, the address, the adapter and the gpioInt are
> >> > defined (or referenced)
> >> > - it presents a Device Specific Method (_DSM) which returns the HID
> >> > Descriptor register address. This register is our entry point for
> >> > retrieving the information about our hid device (so it's mandatory to
> >> > obtain it).
> >> >
> >> > Where am I:
> >> > - I've written a first layer on top of i2c that retrieves the hid
> >> > register (currently the address 0x0001 is hardcoded), then get the
> >> > report desccriptors and the input events, and forward all this stuff
> >> > to the hid layer.
> >> > - It's working with a custom emulated HID over i2c touchpad, while
> >> > waiting for the one a manufacturer should send to me.
> >> > - The detection and the addition to the adapter is done by adding the
> >> > address in the lists and the name through the i2c "->detect" callback
> >> > (which is not very good, because I don't have the interrupt line
> >> > there).
> >> > - I've written a first acpi implementation that rely on the
> >> > DEVICE_ACPI_HANDLE macro to get the ACPI handle of the device (if
> >> > available).
> >> > - I'm not able to do some tests with the ACPI, as I don't know how to
> >> > implement this DSDT on my computer (I'm missing the I2C part), and the
> >> > manufacturer returned the mainboard with the right DSDT to the OEM.
> >> >
> >> > My questions:
> >> > - will the current acpi implementation handle I2C devices?
> >>
> >> you still need to write your own device driver for the device.
> >>
> >> > - it seems to me that the .archdata field is left blank during the i2c
> >> > device initialization in all paths I've seen. Is that true?
> >> > - who puts the name int the struct i2c_board_info? (for hot-plugged
> >> > i2c devices).
> >> >
> >> > - finally, what is the best way of handling ACPI for those I2C devices:
> >> >    1) everything is fine, I should have the ACPI handle in .archdata.
> >> >    2) someone has to implement the handling of I2C in the pnpACPI layer
> >> > (by adding I2CSerialBus handling and creating there the i2c slave).
> >> >    3) I should create an acpi driver which handles "PNP0C50" and which
> >> > creates the i2c slaves.
> >> >
> >> exactly.
> >>
> >> As this I2C controller uses the GPIO interrupt, we need an ACPI GPIO
> >> controller driver for interrupts first.
> >> I already have such a patch in hand, but have not release it for some
> >> reason.
> >> Second, you need to write your own PNP I2C controller driver, to
> >> enumerate the I2C controller via ACPI, AND enumerate the I2C slave
> >> devices under this controller to I2C bus. I also have a similar driver
> >> for SPI controller and SD/MMC controller.
> >> Third, you need a I2C slave device driver to handle the I2C slave device
> >> in I2C bus.
> >>
> >> here is a BKM I wrote, hope it helps.
> >>
> >> And also any comments are welcome. :)
> >>
> >> From 0a0fa4ff7b4b06c6560de94a78b15c6adfd86e34 Mon Sep 17 00:00:00 2001
> >> From: Zhang Rui <rui.zhang@intel.com>
> >> Date: Mon, 26 Dec 2011 10:42:04 +0800
> >>
> >>  As many SoC IP blocks are not hardware self-enumerable, the
> >>  firmware, aka, ACPI tables, is responsible for
> >>  enumerating/reserving/assigning system resources to these
> >>  devices. This tutorial talks about how to enumerate these
> >>  devices via ACPI namespace.
> >>
> >> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> >> ---
> >>  Documentation/acpi/acpi-device-probing.txt |  466
> >> ++++++++++++++++++++++++++++
> >>  1 file changed, 466 insertions(+)
> >>  create mode 100644 Documentation/acpi/acpi-device-probing.txt
> >>
> >> diff --git a/Documentation/acpi/acpi-device-probing.txt
> >> b/Documentation/acpi/acpi-device-probing.txt
> >> new file mode 100644
> >> index 0000000..82efbf3
> >> --- /dev/null
> >> +++ b/Documentation/acpi/acpi-device-probing.txt
> >> @@ -0,0 +1,466 @@
> >> +
> >> +HOWTO enumerate devices via ACPI
> >> +
> >> +Copyright (c) 2011-2012 Intel Corporation
> >> +
> >> +Contrast to hardware self-enumerable devices(e.g. USB, PCI) on PC
> >> platform,
> >> +many SoC IP blocks can not be self enumerated.
> >> +We used to introduce platform specific code for these devices.
> >> +But now, with ACPI 5.0, there is no requirement for the hardware to be
> >> +self-discoverable, enumerable or re-locatable, as the firmware is
> >> responsible
> >> +for enumerating/reserving/assigning system resources (such as address
> >> ranges or
> >> +interrupts) to the device.
> >> +
> >> +This document will show how to enumerate and configure a device via
> >> ACPI.
> >> +If you want to get more details about why and when we need this,
> >> +please refer to ACPI spec 5.0 and
> >> +Intel Architecture Platform Compatibility Definition.
> >> +
> >> +Note that although these are ACPI devices, we prefer to use PnP drivers
> >> for them,
> >> +this is because:
> >> +1. all the non-ACPI-predefined Devices are exported as PnP devices as
> >> well
> >> +2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
> >> work
> >> +   for the device driver, e.g. getting & parsing ACPI resources.
> >> +
> >> +=============================================================================
> >> +1. Understand device definition in ACPI namespace
> >> +   [Case study 1] SD/MMC controller
> >> +2. Driver for a leaf device
> >> +   2.1 Make a list of supported PnP ids
> >> +   2.2 Implement .probe/.remove callbacks for the PnP driver
> >> +   2.3 Fill in the pnp_driver structure
> >> +   2.4 Register the PnP driver
> >> +3. Driver for a master device on a non-self-enumerable bus
> >> +   [Case Study 2] SPI controller and its slave device
> >> +   3.1 Probe the master device
> >> +   3.2 Walk ACPI namesapce to get the child devices of the master
> >> device
> >> +   3.3 Register these child devices as slave devices
> >> +   3.4 Write slave device driver
> >> +4. Misc
> >> +=============================================================================
> >> +
> >> +-----------------------------------------------------------------------------
> >> +1. Understand device definition in ACPI namespace
> >> +-----------------------------------------------------------------------------
> >> +
> >> +To enumerate a device in ACPI namespace, we need to find out and
> >> understand
> >> +HOW the device is defined in ACPI namespace first.
> >> +
> >> +[Case study 1 ] SD/MMC Controller
> >> +
> >> +Here is an ASL example code for SD/MMC controller definition in ACPI
> >> namespace.
> >> +
> >> +        Device (EMMC)
> >> +        {
> >> +            Name (_ADR, Zero)
> >> +            /* I use PNPXXXX, an arbitrary string, here, as PnP id is
> >> device specific */
> >> +            Name (_HID, "PNPXXXX")
> >> +            Name (_CID, "PNPXXXX")
> >> +            Name (_UID, 4)
> >> +
> >> +            Method (_CRS, 0, NotSerialized)
> >> +            {
> >> +                Name (RBUF, ResourceTemplate ()
> >> +                {
> >> +                    Memory32Fixed (ReadWrite,
> >> +                        0xFFA50000,         // Address Base
> >> +                        0x00000100,         // Address Length
> >> +                        )
> >> +                    Interrupt (ResourceConsumer, Level, ActiveLow,
> >> Exclusive, ,, )
> >> +                    {
> >> +                        0x0000001b,
> >> +                    }
> >> +                })
> >> +                Return (RBUF)
> >> +            }
> >> +
> >> +            Method (_STA, 0, NotSerialized)
> >> +            {
> >> +                Return (0x0F)
> >> +            }
> >> +        }
> >> +
> >> +_ADR : the address of this device on its parent bus. Useless in this
> >> case.
> >> +_HID : the PnP id for this device.
> >> +_CID : the compatible PnP id. use this as the PnP id if _HID doesn't
> >> exist.
> >> +_CRS : the system resources currently allocated to this device.
> >> +       the Memory32Fixed part shows an Mem space for the device,
> >> +       and the Interrupt part shows the device interrupt.
> >> +_STA : the current status of the device, e.g. it's
> >> enabled/disabled/removed.
> >> +
> >> +By reading this example ASL code, we should know that there is a SD/MMC
> >> controller
> >> +on this platform, it's mem space base address is 0xFFA50000, length is
> >> 0x00000100,
> >> +and the irq for this device is 0x1b.
> >> +
> >> +In Chapter 2, we will use this piece of ASL code as an example to
> >> +show how to probe the SD/MMC controller via ACPI namespace.
> >> +
> >> +-----------------------------------------------------------------------------
> >> +2 Driver for a leaf device
> >> +-----------------------------------------------------------------------------
> >> +
> >> +2.1 Make a list of supported pnp ids.
> >> +
> >> +Use the string in _HID or _CID objects as the PnP ids so that the
> >> device can
> >> +be attached to the driver successfully.
> >> +
> >> +In this case,
> >> +struct pnp_device_id sdhci_pnp_ids[] = {
> >> +        { .id = "PNPXXXX",
> >> +          .driver_data = (unsigned long)&sdhci_mfd_pdata },
> >> +        { },
> >> +};
> >> +
> >> +2.2 Implement the .probe and .remove callback of PnP driver.
> >> +
> >> +If you're not clear about what should be done in the driver, you can
> >> consult
> >> +some similar driver, for example, drivers/mmc/host/sdhci-pci.c shows
> >> how
> >> +to probe a PCI SD/MMC controller, this helps us understand what should
> >> be done
> >> +in the .probe/.remove callback.
> >> +
> >> +By reading the sdhci-pci .probe function, we know that the .probe
> >> callback
> >> +needs to
> >> +a) alloc a sdhci host.
> >> +b) fill the sdhci host structure with necessary resources got from
> >> +   PCI configure space, including irq and mem space for the sdhci host.
> >> +c) register the sdhci host.
> >> +And then, driver/mmc/host/sdhci.c, the SDHCI interface driver will
> >> handle
> >> +everything for us.
> >> +
> >> +So, basically, we need to do the same work in sdhci_pnp_probe callback,
> >> +except that we need to get the information from ACPI namesapce instead.
> >> +
> >> +To get the resources in _CRS, we do not need Linux ACPICA APIs as PnP
> >> layer
> >> +has done this for us already.
> >> +
> >> +pnp_irq() returns the device irq, which equals the "Interrupt" part in
> >> _CRS method.
> >> +pnp_get_resource(, IORESOURCE_MEM, 0) returns the first Mem space base
> >> address
> >> +and length of this device, which equals the "Memory32Fixed" Part of the
> >> _CRS.
> >> +
> >> +the code below shows how to use the PnP APIs to get ACPI resources and
> >> +register a sdhci host in the .probe callback.
> >> +
> >> +static int __devinit
> >> +sdhci_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
> >> *dev_id)
> >> +{
> >> +...
> >> +     pnp_disable_dev(pdev);
> >> +     ret = pnp_activate_dev(pdev);
> >> +...
> >> +     iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +...
> >> +     host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pnp_dev));
> >> +...
> >> +     host->irq = pnp_irq(pdev, 0);
> >> +...
> >> +        if (!request_mem_region(iomem->start, resource_size(iomem),
> >> +                        mmc_hostname(host->mmc))) {
> >> +...
> >> +        host->ioaddr = ioremap_nocache(iomem->start,
> >> resource_size(iomem));
> >> +...
> >> +     ret = sdhci_add_host(host);
> >> +...
> >> +     pnp_set_drvdata(pdev, sdhci);
> >> +...
> >> +}
> >> +
> >> +Once the .probe callback is done, we just need to release the resources
> >> and
> >> +unregister the host in the .remove callback.
> >> +
> >> +static void sdhci_pnp_remove(struct pnp_dev * pdev)
> >> +{
> >> +     struct sdhci_pnp_dev *sdhci = pnp_get_drvdata(pdev);
> >> +     struct resources *iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +...
> >> +     sdhci_remove_host(sdhci->host, dead);
> >> +     sdhci_free_host(sdhci->host);
> >> +     iounmap(sdhci->host->ioaddr);
> >> +     release_mem_region(iomem->start, resource_size(iomem));
> >> +     pnp_set_drvdata(pdev, NULL);
> >> +     pnp_disable_dev(pdev);
> >> +}
> >> +
> >> +2.3 Fill in the pnp_driver structure
> >> +
> >> +Next step is to fill in the pnp_driver structure with PnP ids and
> >> +.probe/.remove callbacks finished in section 2.1 and 2.2
> >> +
> >> +static struct pnp_driver sdhci_pnp_driver = {
> >> +        .name =         DRIVER_NAME,
> >> +        .id_table =     sdhci_pnp_ids,
> >> +        .probe =        sdhci_pnp_probe,
> >> +        .remove =       __devexit_p(sdhci_pnp_remove),
> >> +};
> >> +
> >> +Note that .name and .id_table cannot be NULL.
> >> +
> >> +2.4 Register the PnP driver
> >> +
> >> +Now we can register this PnP driver to the driver model.
> >> +
> >> +static int __init sdhci_pnp_init(void)
> >> +{
> >> +     return pnp_register_driver(&sdhci_pnp_driver);
> >> +}
> >> +
> >> +module_init(sdhci_pnp_init);
> >> +
> >> +
> >> +-----------------------------------------------------------------------------
> >> +3 Driver for a master device on a non-self-enumerable bus
> >> +-----------------------------------------------------------------------------
> >> +In some cases, enumerating via ACPI brings new requirements in the
> >> driver.
> >> +For example, the driver for a master device on a non-self-enumerable
> >> bus is
> >> +responsible for enumerating the slave devices on this bus as well,
> >> which are
> >> +described as child devices of this master device in ACPI namespace.
> >> +
> >> +Taking SPI bus for example,
> >> +
> >> +-------------------------------------------------------------------
> >> +PNP/ACPI layer
> >> +
> >> +   spi-acpi driver
> >> +         |
> >> +         |-----------------|
> >> +         |                 |
> >> +         |                 |
> >> +         V                 V
> >> +   register itself    register its children
> >> +   as a master        as slave devices
> >> +   device                  |
> >> +         |                 |
> >> +---------|-----------------|---------------------------------------
> >> +         |                 |
> >> +         |                 |
> >> +         |                 |
> >> +         V                 V
> >> +     --------------      -----------
> >> +     |   SPI      |      |  SPI    |
> >> +     |   master   |      |  slave  |
> >> +     --------------      -----------
> >> +                           ^
> >> +                           |
> >> +                           |
> >> +                           V
> >> +                         -----------------------------
> >> +                         |  SPI slave driver driver  |
> >> +                         -----------------------------
> >> +SPI Bus layer
> >> +-------------------------------------------------------------------
> >> +
> >> +The figure above shows the components needed to make a SPI slave device
> >> work
> >> +a) an PNP/ACPI driver to probe the SPI master and its slaves.
> >> +b) a SPI slave device driver for the SPI slave device.
> >> +
> >> +[Case Study 2] SPI controller and its slave device
> >> +
> >> +This piece of ASL code shows the definition of a SPI controller and its
> >> slave device,
> >> +MAX3110, in ACPI namespace.
> >> +
> >> +Device (SPI1) {
> >> +     Name (_ADR, 0)
> >> +     Name (_HID, "PNPYYYY")
> >> +     Name (_CID, "PNPYYYY")
> >> +     Name (_UID, 1)
> >> +
> >> +     Method (_CRS, 0x0, NotSerialized) {
> >> +             Name (RBUF, ResourceTemplate ()
> >> +             {
> >> +                     Memory32Fixed (ReadWrite, 0xff128400, 0x00000400)
> >> +                     Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive, , , )
> >> {0x09}
> >> +             })
> >> +             Return (RBUF)
> >> +     }
> >> +
> >> +     Method (_STA, 0x0, NotSerialized) {
> >> +             Return(0xf)
> >> +     }
> >> +
> >> +     Device(MAX0)
> >> +     {
> >> +             Name(_HID, "PNPZZZZ")          // Max3110 serial port
> >> +             Name(_DDN, "Max3110 serial port")
> >> +             Method(_CRS, 0x0, NotSerialized)
> >> +             {
> >> +                     // SpiSerial Bus Connection Descriptor
> >> +                     Name(UBUF, ResourceTemplate () {
> >> +                             SPISerialBus(
> >> +                             1,                 // Device selection
> >> +                             PolarityHigh,                       // Device selection polarity
> >> +                             ThreeWireMode,                       // wiremode
> >> +                             8,                   // databit len
> >> +                             ControllerInitiated,                       // slave mode
> >> +                             1000,                       // Connection speed
> >> +                             ClockPolarityHigh,                       // Clock polarity
> >> +                             ClockPhaseFirst,                     // clock phase
> >> +                             "\\_SB.SPI1",           // ResourceSource: SPI bus controller name
> >> +                             0,                      // ResourceSourceIndex
> >> +                             ResourceConsumer,                       // Resource usage
> >> +                             ,                       // DescriptorName: creates name for offset
> >> of resource descriptor
> >> +                             )                      // Vendor Data
> >> +                             // OUT pin, BT_EN pin Core GPIO 74
> >> +                             GpioIo(Exclusive, PullDefault, 0, 0, IoRestrictionOutputOnly, "\
> >> \_SB.GPIS", ) {0x4A}
> >> +                     })
> >> +
> >> +                     Return (UBUF)
> >> +             }
> >> +     }
> >> +}
> >> +
> >> +By reading the ASL code, we can see that
> >> +a) There is a SPI controller on this platform.
> >> +   with IRQ 0x09, and a 0x400 bytes Memory space started from
> >> 0xff128400.
> >> +b) a MAX3110 device is connect to a SPI controller.
> >> +   all the information required for probing a SPI slave device is
> >> described
> >> +   in the "SPISerailBus" part of the MAX0._CRS method.
> >> +
> >> +We will talk about how to probe these two devices in this chapter.
> >> +
> >> +3.1 Probe the master device
> >> +
> >> +Please follow the Chapter 2 to probe the SPI master device.
> >> +
> >> +static int __devinit
> >> +dw_spi_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
> >> *dev_id)
> >> +{
> >> +...
> >> +     dws->paddr = pnp_mem_start(pdev, 0);
> >> +     dws->iolen = pnp_mem_len(pdev, 0);
> >> +     dws->irq = pnp_irq(pdev, 0);
> >> +     dws->parent_dev = &pdev->dev;
> >> +     dws->bus_num = index++;
> >> +     dws->num_cs = 4;
> >> +     dws->regs = ioremap_nocache((unsigned long)dws->paddr,
> >> +                             dws->iolen);
> >> +...
> >> +     ret = dw_spi_mid_init(dws);
> >> +...
> >> +     ret = dw_spi_add_host(dws);
> >> +...
> >> +}
> >> +
> >> +3.2 Walk ACPI namespace to probe all its child devices.
> >> +
> >> +As MAX3110 can not be enumerated automatically, we introduce
> >> +dw_spi_pnp_slaves_register() to find the MAX3110 device in ACPI
> >> namespace
> >> +
> >> +static int __devinit dw_spi_pnp_slaves_register(struct dw_spi_pnp*
> >> dwpnp)
> >> +{
> >> +     ...
> >> +     struct acpi_device *adev;
> >> +     adev = dwpnp->pdev->data;
> >> +
> >> +     /*
> >> +      * find spi child devices given in ACPI namespace, one lower level
> >> only
> >> +      */
> >> +     status = acpi_walk_namespace(ACPI_TYPE_DEVICE, adev->handle, 1,
> >> +                                  spi_slave_register, NULL,
> >> +                                  spi_slave_info, NULL);
> >> +     ...
> >> +}
> >> +
> >> +3.3 Register its child devices as slave devices
> >> +
> >> +As spi_slave_register is invoked for each SPI1 child device,
> >> +we introduce spi_slave_fill_resourcetry and try to register
> >> +SPI slave devices in spi_slave_register.
> >> +
> >> +acpi_status __init spi_slave_register(acpi_handle spi_slave_handle, u32
> >> level,
> >> +                                   void* data, void** return_value)
> >> +{
> >> +     ...
> >> +     struct spi_board_info *spi_slave_info;
> >> +     ...
> >> +     status = acpi_walk_resources(spi_slave_handle, METHOD_NAME__CRS,
> >> +                                  spi_slave_fill_resource, data);
> >> +     ...
> >> +     /* register SPI slave device */
> >> +     ret = spi_register_board_info(spi_slave_info, 1);
> >> +     ...
> >> +}
> >> +
> >> +acpi_status __devinit spi_slave_fill_resource(struct acpi_resource
> >> *resource, void* data)
> >> +{
> >> +     struct spi_board_info *spi_slave_info;
> >> +     struct acpi_resource_spi_serialbus *spi_resource;
> >> +     ...
> >> +             spi_resource = &resource->data.spi_serial_bus;
> >> +             spi_slave_info->chip_select = spi_resource->device_selection;
> >> +             spi_slave_info->max_speed_hz = spi_resource->connection_speed;
> >> +             spi_slave_info->mode = (spi_resource->clock_phase ? SPI_CPHA : 0) |
> >> +                     (spi_resource->clock_polarity ? SPI_CPOL : 0) |
> >> +                     (spi_resource->device_polarity ? SPI_CS_HIGH : 0) |
> >> +                     (spi_resource->wire_mode ? SPI_3WIRE : 0);
> >> +     ...
> >> +}
> >> +
> >> +3.4 Write the slave device driver
> >> +
> >> +After 3.3 is done, the MAX3110 device is an slave device in the SPI
> >> bus,
> >> +but to make it work properly, we still need a SPI slave device driver.
> >> +
> >> +Note that this is a general SPI drivers independent of ACPI.
> >> +
> >> +We will not go into details of the slave device driver here as
> >> +this piece of code is bus/device specific.
> >> +
> >> +-----------------------------------------------------------------------------
> >> +4 Misc
> >> +-----------------------------------------------------------------------------
> >> +
> >> +4.1 Note
> >> +
> >> +As ACPI 5.0 is still in heavily developing, if you are unable to find
> >> out all the
> >> +required information for probing a device in ACPI namespace, it is
> >> possible
> >> +that the ASL code is not well written.
> >> +Please contact Zhang Rui <rui.zhang@intel.com> with the acpidump output
> >> of your
> >> +platform attached if you suspect it's an BIOS problem.
> >> +
> >> +4.2 Some important ACPICA APIs for device driver implementation:
> >> +
> >> +-- acpi_status
> >> +   acpi_walk_namespace(acpi_object_type type,
> >> +                    acpi_handle start_object,
> >> +                    u32 max_depth,
> >> +                    acpi_walk_callback pre_order_visit,
> >> +                    acpi_walk_callback post_order_visit,
> >> +                    void *context, void **return_value);
> >> +Traverse ACPI namespace subtree rooted at start_object, go down
> >> max_depth level
> >> +at most. Call pre_order_visit when the proper node with type is found
> >> the first
> >> +time, call post_order_visit is the node is previously visited. Context
> >> and
> >> +return_value is passed down during the traverse.
> >> +
> >> +And the prototype of acpi_walk_callback:
> >> +typedef
> >> +acpi_status(*acpi_walk_callback) (acpi_handle object,
> >> +                               u32 nesting_level,
> >> +                               void *context, void **return_value);
> >> +
> >> +-- acpi_status
> >> +   acpi_get_handle(acpi_handle parent,
> >> +                acpi_string pathname, acpi_handle * ret_handle);
> >> +Try to get handle with specified pathname under node parent. Usually
> >> used to
> >> +check whether a particular node is available or not.
> >> +
> >> +-- acpi_status
> >> +   acpi_get_object_info(acpi_handle object,
> >> +                     struct acpi_device_info **return_buffer);
> >> +Get acpi_device_info from object handle. Useful for retrieving ACPI
> >> object
> >> +name, type, and status etc.
> >> +
> >> +-- acpi_status
> >> +   acpi_walk_resources(acpi_handle device,
> >> +                    char *name,
> >> +                    acpi_walk_resource_callback user_function, void *context);
> >> +Traverse resource node specified by name(e.g. METHOD_NAME__CRS) in ACPI
> >> +namespace subtree rooted at device. Call user_function for each entry
> >> in
> >> +acpi_resource list. The list may containe acpi_resource entries with
> >> various
> >> +types. So it is important to handle the interested resource type
> >> properly.
> >> +The acpi_resource with ACPI_RESOURCE_TYPE_END_TAG indicates
> >> end-of-list.
> >> +
> >> +And the prototype of acpi_walk_resource_callback:
> >> +typedef
> >> +acpi_status(*acpi_walk_resource_callback) (struct acpi_resource *
> >> resource,
> >> +                                        void *context);
> >> +
> >> +More ACPICA external interfaces available in include/acpi/acpixf.h
> >
> >


--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
lan,Tianyu July 9, 2012, 3:24 a.m. UTC | #5
On 2012?07?06? 13:52, Mika Westerberg wrote:
> On Thu, Jul 05, 2012 at 03:01:57PM +0800, Zhang Rui wrote:
>> +Note that although these are ACPI devices, we prefer to use PnP drivers
>> for them,
>> +this is because:
>> +1. all the non-ACPI-predefined Devices are exported as PnP devices as
>> well
>> +2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
>> work
>> +   for the device driver, e.g. getting&  parsing ACPI resources.
>
> (Nice BKM, thanks for sharing)
>
> I have few questions about using PnP drivers instead of pure ACPI drivers.
>
> ACPI 5.0 defined some new resources, for example "Fixed DMA descriptor"
> that has information about the request line + channel for the device to
> use. Hovewer, PnP drivers pass resources as 'struct resource', which
> basically only has start and end - how do you represent all this new stuff
> using 'struct resource'?
>
I think we can add new interface to get acpi specific resources. e.g
struct acpi_resource pnp_get_acpi_resource(...). When the pnp acpi devices
were initialized, put those acpi specific resources into a new resource list
pnpdev->acpi_resources. What pnp_get_acpi_resource does is to get specified
type acpi resources and return. We also need to define some acpi resource types.

ACPI_RESOURCE_DMA
ACPI_RESOURCE_I2C_SERIALBUS
ACPI_RESOURCE_SPI_SERIALBUS
ACPI_RESOURCE_UART_SERIALBUS
ACPI_RESOURCE_COMMON_SERIALBUS
...

How about this? welcome to comments.

> Or should we use acpi_walk_resources() where 'struct resource' is not
> suitable?
>
Moore, Robert July 9, 2012, 4:02 a.m. UTC | #6
These are already defined in acpica - in the file acrestyp.h

    ACPI_RESOURCE_FIXED_DMA                 FixedDma;

    ACPI_RESOURCE_GPIO                      Gpio;
    ACPI_RESOURCE_I2C_SERIALBUS             I2cSerialBus;
    ACPI_RESOURCE_SPI_SERIALBUS             SpiSerialBus;
    ACPI_RESOURCE_UART_SERIALBUS            UartSerialBus;
    ACPI_RESOURCE_COMMON_SERIALBUS          CommonSerialBus;



>-----Original Message-----
>From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
>owner@vger.kernel.org] On Behalf Of Lan Tianyu
>Sent: Sunday, July 08, 2012 8:25 PM
>To: Mika Westerberg
>Cc: Zhang, Rui; khali@linux-fr.org; ben-linux@fluff.org;
>w.sang@pengutronix.de; lenb@kernel.org; linux-acpi@vger.kernel.org; linux-
>i2c@vger.kernel.org; linux-kernel@vger.kernel.org; jkosina@suse.cz;
>chatty@enac.fr; jj_ding@emc.com.tw; bhelgaas@google.com; abelay@mit.edu
>Subject: Re: Fwd: Hid over I2C and ACPI interaction
>
>On 2012?07?06? 13:52, Mika Westerberg wrote:
>> On Thu, Jul 05, 2012 at 03:01:57PM +0800, Zhang Rui wrote:
>>> +Note that although these are ACPI devices, we prefer to use PnP drivers
>>> for them,
>>> +this is because:
>>> +1. all the non-ACPI-predefined Devices are exported as PnP devices as
>>> well
>>> +2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
>>> work
>>> +   for the device driver, e.g. getting&  parsing ACPI resources.
>>
>> (Nice BKM, thanks for sharing)
>>
>> I have few questions about using PnP drivers instead of pure ACPI
>drivers.
>>
>> ACPI 5.0 defined some new resources, for example "Fixed DMA descriptor"
>> that has information about the request line + channel for the device to
>> use. Hovewer, PnP drivers pass resources as 'struct resource', which
>> basically only has start and end - how do you represent all this new
>stuff
>> using 'struct resource'?
>>
>I think we can add new interface to get acpi specific resources. e.g
>struct acpi_resource pnp_get_acpi_resource(...). When the pnp acpi devices
>were initialized, put those acpi specific resources into a new resource
>list
>pnpdev->acpi_resources. What pnp_get_acpi_resource does is to get specified
>type acpi resources and return. We also need to define some acpi resource
>types.
>
>ACPI_RESOURCE_DMA
>ACPI_RESOURCE_I2C_SERIALBUS
>ACPI_RESOURCE_SPI_SERIALBUS
>ACPI_RESOURCE_UART_SERIALBUS
>ACPI_RESOURCE_COMMON_SERIALBUS
>...
>
>How about this? welcome to comments.
>
>> Or should we use acpi_walk_resources() where 'struct resource' is not
>> suitable?
>>
>
>--
>Best Regards
>Tianyu Lan
>linux kernel enabling team
>--
>To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
lan,Tianyu July 9, 2012, 7:28 a.m. UTC | #7
On 2012?07?09? 12:02, Moore, Robert wrote:
> These are already defined in acpica - in the file acrestyp.h
> 
>      ACPI_RESOURCE_FIXED_DMA                 FixedDma;
> 
>      ACPI_RESOURCE_GPIO                      Gpio;
>      ACPI_RESOURCE_I2C_SERIALBUS             I2cSerialBus;
>      ACPI_RESOURCE_SPI_SERIALBUS             SpiSerialBus;
>      ACPI_RESOURCE_UART_SERIALBUS            UartSerialBus;
>      ACPI_RESOURCE_COMMON_SERIALBUS          CommonSerialBus;
> 
Yeah. Thanks for Bob's reminder. We can reuse these macros.

> 
> 
>> -----Original Message-----
>> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
>> owner@vger.kernel.org] On Behalf Of Lan Tianyu
>> Sent: Sunday, July 08, 2012 8:25 PM
>> To: Mika Westerberg
>> Cc: Zhang, Rui; khali@linux-fr.org; ben-linux@fluff.org;
>> w.sang@pengutronix.de; lenb@kernel.org; linux-acpi@vger.kernel.org; linux-
>> i2c@vger.kernel.org; linux-kernel@vger.kernel.org; jkosina@suse.cz;
>> chatty@enac.fr; jj_ding@emc.com.tw; bhelgaas@google.com; abelay@mit.edu
>> Subject: Re: Fwd: Hid over I2C and ACPI interaction
>>
>> On 2012?07?06? 13:52, Mika Westerberg wrote:
>>> On Thu, Jul 05, 2012 at 03:01:57PM +0800, Zhang Rui wrote:
>>>> +Note that although these are ACPI devices, we prefer to use PnP drivers
>>>> for them,
>>>> +this is because:
>>>> +1. all the non-ACPI-predefined Devices are exported as PnP devices as
>>>> well
>>>> +2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
>>>> work
>>>> +   for the device driver, e.g. getting&   parsing ACPI resources.
>>>
>>> (Nice BKM, thanks for sharing)
>>>
>>> I have few questions about using PnP drivers instead of pure ACPI
>> drivers.
>>>
>>> ACPI 5.0 defined some new resources, for example "Fixed DMA descriptor"
>>> that has information about the request line + channel for the device to
>>> use. Hovewer, PnP drivers pass resources as 'struct resource', which
>>> basically only has start and end - how do you represent all this new
>> stuff
>>> using 'struct resource'?
>>>
>> I think we can add new interface to get acpi specific resources. e.g
>> struct acpi_resource pnp_get_acpi_resource(...). When the pnp acpi devices
>> were initialized, put those acpi specific resources into a new resource
>> list
>> pnpdev->acpi_resources. What pnp_get_acpi_resource does is to get specified
>> type acpi resources and return. We also need to define some acpi resource
>> types.
>>
>> ACPI_RESOURCE_DMA
>> ACPI_RESOURCE_I2C_SERIALBUS
>> ACPI_RESOURCE_SPI_SERIALBUS
>> ACPI_RESOURCE_UART_SERIALBUS
>> ACPI_RESOURCE_COMMON_SERIALBUS
>> ...
>>
>> How about this? welcome to comments.
>>
>>> Or should we use acpi_walk_resources() where 'struct resource' is not
>>> suitable?
>>>
>>
>> --
>> Best Regards
>> Tianyu Lan
>> linux kernel enabling team
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mika Westerberg July 9, 2012, 7:51 a.m. UTC | #8
On Mon, Jul 09, 2012 at 11:24:45AM +0800, Lan Tianyu wrote:
> I think we can add new interface to get acpi specific resources. e.g
> struct acpi_resource pnp_get_acpi_resource(...). When the pnp acpi devices
> were initialized, put those acpi specific resources into a new resource list
> pnpdev->acpi_resources. What pnp_get_acpi_resource does is to get specified
> type acpi resources and return. We also need to define some acpi resource types.

Yeah, that sounds good to me.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/acpi/acpi-device-probing.txt
b/Documentation/acpi/acpi-device-probing.txt
new file mode 100644
index 0000000..82efbf3
--- /dev/null
+++ b/Documentation/acpi/acpi-device-probing.txt
@@ -0,0 +1,466 @@ 
+
+HOWTO enumerate devices via ACPI
+
+Copyright (c) 2011-2012 Intel Corporation
+
+Contrast to hardware self-enumerable devices(e.g. USB, PCI) on PC
platform,
+many SoC IP blocks can not be self enumerated.
+We used to introduce platform specific code for these devices.
+But now, with ACPI 5.0, there is no requirement for the hardware to be
+self-discoverable, enumerable or re-locatable, as the firmware is
responsible
+for enumerating/reserving/assigning system resources (such as address
ranges or
+interrupts) to the device.
+
+This document will show how to enumerate and configure a device via
ACPI.
+If you want to get more details about why and when we need this,
+please refer to ACPI spec 5.0 and
+Intel Architecture Platform Compatibility Definition.
+
+Note that although these are ACPI devices, we prefer to use PnP drivers
for them,
+this is because:
+1. all the non-ACPI-predefined Devices are exported as PnP devices as
well
+2. PnP bus is a well designed bus. Probing via PnP layer saves a lot of
work
+   for the device driver, e.g. getting & parsing ACPI resources.
+
+=============================================================================
+1. Understand device definition in ACPI namespace
+   [Case study 1] SD/MMC controller
+2. Driver for a leaf device
+   2.1 Make a list of supported PnP ids
+   2.2 Implement .probe/.remove callbacks for the PnP driver
+   2.3 Fill in the pnp_driver structure
+   2.4 Register the PnP driver
+3. Driver for a master device on a non-self-enumerable bus
+   [Case Study 2] SPI controller and its slave device
+   3.1 Probe the master device
+   3.2 Walk ACPI namesapce to get the child devices of the master
device
+   3.3 Register these child devices as slave devices
+   3.4 Write slave device driver
+4. Misc
+=============================================================================
+
+-----------------------------------------------------------------------------
+1. Understand device definition in ACPI namespace
+-----------------------------------------------------------------------------
+
+To enumerate a device in ACPI namespace, we need to find out and
understand
+HOW the device is defined in ACPI namespace first.
+
+[Case study 1 ] SD/MMC Controller
+
+Here is an ASL example code for SD/MMC controller definition in ACPI
namespace.
+
+        Device (EMMC)
+        {
+            Name (_ADR, Zero)
+            /* I use PNPXXXX, an arbitrary string, here, as PnP id is
device specific */
+            Name (_HID, "PNPXXXX")
+            Name (_CID, "PNPXXXX")
+            Name (_UID, 4)
+
+            Method (_CRS, 0, NotSerialized)
+            {
+                Name (RBUF, ResourceTemplate ()
+                {
+                    Memory32Fixed (ReadWrite,
+                        0xFFA50000,         // Address Base
+                        0x00000100,         // Address Length
+                        )
+                    Interrupt (ResourceConsumer, Level, ActiveLow,
Exclusive, ,, )
+                    {
+                        0x0000001b,
+                    }
+                })
+                Return (RBUF)
+            }
+
+            Method (_STA, 0, NotSerialized)
+            {
+                Return (0x0F)
+            }
+        }
+
+_ADR : the address of this device on its parent bus. Useless in this
case.
+_HID : the PnP id for this device.
+_CID : the compatible PnP id. use this as the PnP id if _HID doesn't
exist.
+_CRS : the system resources currently allocated to this device.
+       the Memory32Fixed part shows an Mem space for the device,
+       and the Interrupt part shows the device interrupt.
+_STA : the current status of the device, e.g. it's
enabled/disabled/removed.
+
+By reading this example ASL code, we should know that there is a SD/MMC
controller
+on this platform, it's mem space base address is 0xFFA50000, length is
0x00000100,
+and the irq for this device is 0x1b.
+
+In Chapter 2, we will use this piece of ASL code as an example to
+show how to probe the SD/MMC controller via ACPI namespace.
+
+-----------------------------------------------------------------------------
+2 Driver for a leaf device
+-----------------------------------------------------------------------------
+
+2.1 Make a list of supported pnp ids.
+
+Use the string in _HID or _CID objects as the PnP ids so that the
device can
+be attached to the driver successfully.
+
+In this case,
+struct pnp_device_id sdhci_pnp_ids[] = {
+        { .id = "PNPXXXX",
+          .driver_data = (unsigned long)&sdhci_mfd_pdata },
+        { },
+};
+
+2.2 Implement the .probe and .remove callback of PnP driver.
+
+If you're not clear about what should be done in the driver, you can
consult
+some similar driver, for example, drivers/mmc/host/sdhci-pci.c shows
how
+to probe a PCI SD/MMC controller, this helps us understand what should
be done
+in the .probe/.remove callback.
+
+By reading the sdhci-pci .probe function, we know that the .probe
callback
+needs to
+a) alloc a sdhci host.
+b) fill the sdhci host structure with necessary resources got from
+   PCI configure space, including irq and mem space for the sdhci host.
+c) register the sdhci host.
+And then, driver/mmc/host/sdhci.c, the SDHCI interface driver will
handle
+everything for us.
+
+So, basically, we need to do the same work in sdhci_pnp_probe callback,
+except that we need to get the information from ACPI namesapce instead.
+
+To get the resources in _CRS, we do not need Linux ACPICA APIs as PnP
layer
+has done this for us already.
+
+pnp_irq() returns the device irq, which equals the "Interrupt" part in
_CRS method.
+pnp_get_resource(, IORESOURCE_MEM, 0) returns the first Mem space base
address
+and length of this device, which equals the "Memory32Fixed" Part of the
_CRS.
+
+the code below shows how to use the PnP APIs to get ACPI resources and
+register a sdhci host in the .probe callback.
+
+static int __devinit
+sdhci_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
*dev_id)
+{
+...
+	pnp_disable_dev(pdev);
+	ret = pnp_activate_dev(pdev);
+...
+	iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
+...
+	host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pnp_dev));
+...
+	host->irq = pnp_irq(pdev, 0);
+...
+        if (!request_mem_region(iomem->start, resource_size(iomem),
+                        mmc_hostname(host->mmc))) {
+...
+        host->ioaddr = ioremap_nocache(iomem->start,
resource_size(iomem));
+...
+	ret = sdhci_add_host(host);
+...
+	pnp_set_drvdata(pdev, sdhci);
+...
+}
+
+Once the .probe callback is done, we just need to release the resources
and
+unregister the host in the .remove callback.
+
+static void sdhci_pnp_remove(struct pnp_dev * pdev)
+{
+	struct sdhci_pnp_dev *sdhci = pnp_get_drvdata(pdev);
+	struct resources *iomem = pnp_get_resource(pdev, IORESOURCE_MEM, 0);
+...
+	sdhci_remove_host(sdhci->host, dead);
+	sdhci_free_host(sdhci->host);
+	iounmap(sdhci->host->ioaddr);
+	release_mem_region(iomem->start, resource_size(iomem));
+	pnp_set_drvdata(pdev, NULL);
+	pnp_disable_dev(pdev);
+}
+
+2.3 Fill in the pnp_driver structure
+
+Next step is to fill in the pnp_driver structure with PnP ids and
+.probe/.remove callbacks finished in section 2.1 and 2.2
+
+static struct pnp_driver sdhci_pnp_driver = {
+        .name =         DRIVER_NAME,
+        .id_table =     sdhci_pnp_ids,
+        .probe =        sdhci_pnp_probe,
+        .remove =       __devexit_p(sdhci_pnp_remove),
+};
+
+Note that .name and .id_table cannot be NULL.
+
+2.4 Register the PnP driver
+
+Now we can register this PnP driver to the driver model.
+
+static int __init sdhci_pnp_init(void)
+{
+	return pnp_register_driver(&sdhci_pnp_driver);
+}
+
+module_init(sdhci_pnp_init);
+
+
+-----------------------------------------------------------------------------
+3 Driver for a master device on a non-self-enumerable bus
+-----------------------------------------------------------------------------
+In some cases, enumerating via ACPI brings new requirements in the
driver.
+For example, the driver for a master device on a non-self-enumerable
bus is
+responsible for enumerating the slave devices on this bus as well,
which are
+described as child devices of this master device in ACPI namespace.
+
+Taking SPI bus for example,
+
+-------------------------------------------------------------------
+PNP/ACPI layer
+
+   spi-acpi driver
+         |
+         |-----------------|
+         |                 |
+         |                 |
+         V                 V
+   register itself    register its children
+   as a master        as slave devices
+   device                  |
+         |                 |
+---------|-----------------|---------------------------------------
+         |                 |
+         |                 |
+         |                 |
+         V                 V
+     --------------      -----------
+     |   SPI      |      |  SPI    |
+     |   master   |      |  slave  |
+     --------------      -----------
+                           ^
+                           |
+                           |
+                           V
+                         -----------------------------
+                         |  SPI slave driver driver  |
+                         -----------------------------
+SPI Bus layer
+-------------------------------------------------------------------
+
+The figure above shows the components needed to make a SPI slave device
work
+a) an PNP/ACPI driver to probe the SPI master and its slaves.
+b) a SPI slave device driver for the SPI slave device.
+
+[Case Study 2] SPI controller and its slave device
+
+This piece of ASL code shows the definition of a SPI controller and its
slave device,
+MAX3110, in ACPI namespace.
+
+Device (SPI1) {
+	Name (_ADR, 0)
+	Name (_HID, "PNPYYYY")
+	Name (_CID, "PNPYYYY")
+	Name (_UID, 1)
+
+	Method (_CRS, 0x0, NotSerialized) {
+		Name (RBUF, ResourceTemplate ()
+		{
+			Memory32Fixed (ReadWrite, 0xff128400, 0x00000400)
+			Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive, , , )
{0x09}
+		})
+		Return (RBUF)
+	}
+
+	Method (_STA, 0x0, NotSerialized) {
+		Return(0xf)
+	}
+
+	Device(MAX0)
+	{
+		Name(_HID, "PNPZZZZ")          // Max3110 serial port
+		Name(_DDN, "Max3110 serial port")
+		Method(_CRS, 0x0, NotSerialized)
+		{
+			// SpiSerial Bus Connection Descriptor
+			Name(UBUF, ResourceTemplate () {
+				SPISerialBus(
+				1,                 // Device selection
+				PolarityHigh,                       // Device selection polarity
+				ThreeWireMode,                       // wiremode
+				8,                   // databit len
+				ControllerInitiated,                       // slave mode
+				1000,                       // Connection speed
+				ClockPolarityHigh,                       // Clock polarity
+				ClockPhaseFirst,                     // clock phase
+				"\\_SB.SPI1",           // ResourceSource: SPI bus controller name
+				0,                      // ResourceSourceIndex
+				ResourceConsumer,                       // Resource usage
+				,                       // DescriptorName: creates name for offset
of resource descriptor
+				)                      // Vendor Data
+				// OUT pin, BT_EN pin Core GPIO 74
+				GpioIo(Exclusive, PullDefault, 0, 0, IoRestrictionOutputOnly, "\
\_SB.GPIS", ) {0x4A}
+			})
+
+			Return (UBUF)
+		}
+	}
+}
+
+By reading the ASL code, we can see that
+a) There is a SPI controller on this platform.
+   with IRQ 0x09, and a 0x400 bytes Memory space started from
0xff128400.
+b) a MAX3110 device is connect to a SPI controller.
+   all the information required for probing a SPI slave device is
described
+   in the "SPISerailBus" part of the MAX0._CRS method.
+
+We will talk about how to probe these two devices in this chapter.
+
+3.1 Probe the master device
+
+Please follow the Chapter 2 to probe the SPI master device.
+
+static int __devinit
+dw_spi_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id
*dev_id)
+{
+...
+	dws->paddr = pnp_mem_start(pdev, 0);
+	dws->iolen = pnp_mem_len(pdev, 0);
+	dws->irq = pnp_irq(pdev, 0);
+	dws->parent_dev = &pdev->dev;
+	dws->bus_num = index++;
+	dws->num_cs = 4;
+	dws->regs = ioremap_nocache((unsigned long)dws->paddr,
+				dws->iolen);
+...
+	ret = dw_spi_mid_init(dws);
+...
+	ret = dw_spi_add_host(dws);
+...
+}
+
+3.2 Walk ACPI namespace to probe all its child devices.
+
+As MAX3110 can not be enumerated automatically, we introduce
+dw_spi_pnp_slaves_register() to find the MAX3110 device in ACPI
namespace
+
+static int __devinit dw_spi_pnp_slaves_register(struct dw_spi_pnp*
dwpnp)
+{
+	...
+	struct acpi_device *adev;
+	adev = dwpnp->pdev->data;
+
+	/*
+	 * find spi child devices given in ACPI namespace, one lower level
only
+	 */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, adev->handle, 1,
+				     spi_slave_register, NULL,
+				     spi_slave_info, NULL);
+	...
+}
+
+3.3 Register its child devices as slave devices
+
+As spi_slave_register is invoked for each SPI1 child device,
+we introduce spi_slave_fill_resourcetry and try to register
+SPI slave devices in spi_slave_register.
+
+acpi_status __init spi_slave_register(acpi_handle spi_slave_handle, u32
level,
+				      void* data, void** return_value)
+{
+	...
+	struct spi_board_info *spi_slave_info;
+	...
+	status = acpi_walk_resources(spi_slave_handle, METHOD_NAME__CRS,
+				     spi_slave_fill_resource, data);
+	...
+	/* register SPI slave device */
+	ret = spi_register_board_info(spi_slave_info, 1);
+	...
+}
+
+acpi_status __devinit spi_slave_fill_resource(struct acpi_resource
*resource, void* data)
+{
+	struct spi_board_info *spi_slave_info;
+	struct acpi_resource_spi_serialbus *spi_resource;
+	...
+	  	spi_resource = &resource->data.spi_serial_bus;
+	  	spi_slave_info->chip_select = spi_resource->device_selection;
+	  	spi_slave_info->max_speed_hz = spi_resource->connection_speed;
+	  	spi_slave_info->mode = (spi_resource->clock_phase ? SPI_CPHA : 0) |
+	  		(spi_resource->clock_polarity ? SPI_CPOL : 0) |
+	  		(spi_resource->device_polarity ? SPI_CS_HIGH : 0) |
+	  		(spi_resource->wire_mode ? SPI_3WIRE : 0);
+	...
+}
+
+3.4 Write the slave device driver
+
+After 3.3 is done, the MAX3110 device is an slave device in the SPI
bus,
+but to make it work properly, we still need a SPI slave device driver.
+
+Note that this is a general SPI drivers independent of ACPI.
+
+We will not go into details of the slave device driver here as
+this piece of code is bus/device specific.
+
+-----------------------------------------------------------------------------
+4 Misc
+-----------------------------------------------------------------------------
+
+4.1 Note
+
+As ACPI 5.0 is still in heavily developing, if you are unable to find
out all the
+required information for probing a device in ACPI namespace, it is
possible
+that the ASL code is not well written.
+Please contact Zhang Rui <rui.zhang@intel.com> with the acpidump output
of your