Re: Fwd: Hid over I2C and ACPI interaction

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx> 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@xxxxxxxxx>
>> > To: Jean Delvare <khali@xxxxxxxxxxxx>, Ben Dooks <ben-linux@xxxxxxxxx>, Wolfram
>> > Sang <w.sang@xxxxxxxxxxxxxx>, Len Brown <lenb@xxxxxxxxxx>,
>> > <linux-acpi@xxxxxxxxxxxxxxx>, <linux-i2c@xxxxxxxxxxxxxxx>,
>> > <linux-kernel@xxxxxxxxxxxxxxx>
>> > CC: Jiri Kosina <jkosina@xxxxxxx>, Stéphane Chatty <chatty@xxxxxxx>, JJ Ding
>> > <jj_ding@xxxxxxxxxx>
>> >
>> > 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@xxxxxxxxx>
>> 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@xxxxxxxxx>
>> ---
>>  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@xxxxxxxxx> 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-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux