From: eLinux.org

Linux Drivers Device Tree Guide

Contents

Support of different hardware versions in a single driver

Examples of drivers that match more than one compatible string.

This list is not an endorsement of any particular technique. It is
instead a (partial) list of some existing code in the Linux kernel.

The examples are not meant to capture each method entirely; they are
instead meant to illustrate the basic concept.

Hardware Version in struct of_device_id.data

The hardware version is used throughout the driver to choose alternate
actions.

drivers/iommu/arm-smmu.c:

  1. static const struct of_device_id arm_smmu_of_match[] = {
  2. { .compatible = "arm,smmu-v1", .data = (void *)ARM_SMMU_V1 },
  3. { .compatible = "arm,smmu-v2", .data = (void *)ARM_SMMU_V2 },
  4. { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 },
  5. { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 },
  6. { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 },
  7. { },
  8. };
  9. MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
  10. static int arm_smmu_device_dt_probe(struct platform_device *pdev)
  11. {
  12. const struct of_device_id *of_id;
  13. of_id = of_match_node(arm_smmu_of_match, dev->of_node);
  14. smmu->version = (enum arm_smmu_arch_version)of_id->data;
  15. ...
  16. if (smmu->version > ARM_SMMU_V1) {
  17. ...
  18. }
  19. }
  20. static struct platform_driver arm_smmu_driver = {
  21. .driver = {
  22. .name = "arm-smmu",
  23. .of_match_table = of_match_ptr(arm_smmu_of_match),
  24. },
  25. .probe = arm_smmu_device_dt_probe,
  26. .remove = arm_smmu_device_remove,
  27. };

Function Call Table pointer in struct of_device_id.data

The function call table is used throughout the driver to choose
alternate actions.

drivers/iio/adc/xilinx-xadc-core.c:

  1. static const struct xadc_ops xadc_zynq_ops = {
  2. .read = xadc_zynq_read_adc_reg,
  3. .write = xadc_zynq_write_adc_reg,
  4. .setup = xadc_zynq_setup,
  5. .get_dclk_rate = xadc_zynq_get_dclk_rate,
  6. .interrupt_handler = xadc_zynq_interrupt_handler,
  7. .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler,
  8. .update_alarm = xadc_zynq_update_alarm,
  9. };
  10. static const struct of_device_id xadc_of_match_table[] = {
  11. { .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops },
  12. { .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops },
  13. { },
  14. };
  15. MODULE_DEVICE_TABLE(of, xadc_of_match_table);
  16. static int xadc_probe(struct platform_device *pdev)
  17. {
  18. const struct of_device_id *id;
  19. id = of_match_node(xadc_of_match_table, pdev->dev.of_node);
  20. ...
  21. indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc));
  22. xadc = iio_priv(indio_dev);
  23. ...
  24. xadc->ops = id->data;
  25. ...
  26. ret = xadc->ops->setup(pdev, indio_dev, irq);
  27. ...
  28. }
  29. static struct platform_driver xadc_driver = {
  30. .probe = xadc_probe,
  31. .remove = xadc_remove,
  32. .driver = {
  33. .name = "xadc",
  34. .of_match_table = xadc_of_match_table,
  35. },
  36. };
  37. module_platform_driver(xadc_driver);

Hardware Description pointer in struct of_device_id.data

The hardware description data is used to configure the device.

This struct pointed to by struct of_device_id.data in this example
includes a function call table in addition to the hardware description
fields.

drivers/iio/adc/twl6030-gpadc.c:

  1. static const struct twl6030_gpadc_platform_data twl6030_pdata = {
  2. .iio_channels = twl6030_gpadc_iio_channels,
  3. .nchannels = TWL6030_GPADC_USED_CHANNELS,
  4. .ideal = twl6030_ideal,
  5. .start_conversion = twl6030_start_conversion,
  6. .channel_to_reg = twl6030_channel_to_reg,
  7. .calibrate = twl6030_calibration,
  8. };
  9. static const struct of_device_id of_twl6030_match_tbl[] = {
  10. {
  11. .compatible = "ti,twl6030-gpadc",
  12. .data = &twl6030_pdata,
  13. },
  14. {
  15. .compatible = "ti,twl6032-gpadc",
  16. .data = &twl6032_pdata,
  17. },
  18. { /* end */ }
  19. };
  20. static int twl6030_gpadc_probe(struct platform_device *pdev)
  21. {
  22. const struct of_device_id *match;
  23. const struct twl6030_gpadc_platform_data *pdata;
  24. match = of_match_device(of_twl6030_match_tbl, dev);
  25. pdata = match->data;
  26. indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
  27. gpadc = iio_priv(indio_dev);
  28. gpadc->pdata = pdata;
  29. platform_set_drvdata(pdev, indio_dev);
  30. ...
  31. ret = pdata->calibrate(gpadc);
  32. ...
  33. indio_dev->channels = pdata->iio_channels;
  34. indio_dev->num_channels = pdata->nchannels;
  35. }

Category: