Difference between revisions of "Linux Drivers Device Tree Guide"
(add link to top device tree page) |
(add Linux conventions) |
||
Line 2: | Line 2: | ||
[[Device_Tree | Top Device Tree page]] | [[Device_Tree | Top Device Tree page]] | ||
+ | |||
+ | == Linux conventions == | ||
+ | |||
+ | * hex constants are lower case | ||
+ | ** use "0x" instead of "0X" | ||
+ | ** use a..f instead of A..F, eg 0xf instead of 0xF | ||
+ | |||
+ | * node and property names | ||
+ | ** use "-" instead of "_" | ||
+ | |||
+ | * node names | ||
+ | ** unit-address does not have a leading "0x" (the number is assumed to be hexadecimal) | ||
+ | ** unit-address does not have a leading zeros | ||
+ | |||
+ | * maximum depth of device tree | ||
+ | ** #define FDT_MAX_DEPTH 64 | ||
== Support of different hardware versions in a single driver == | == Support of different hardware versions in a single driver == |
Revision as of 02:12, 20 June 2016
Contents
Linux conventions
- hex constants are lower case
- use "0x" instead of "0X"
- use a..f instead of A..F, eg 0xf instead of 0xF
- node and property names
- use "-" instead of "_"
- node names
- unit-address does not have a leading "0x" (the number is assumed to be hexadecimal)
- unit-address does not have a leading zeros
- maximum depth of device tree
- #define FDT_MAX_DEPTH 64
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:
static const struct of_device_id arm_smmu_of_match[] = { { .compatible = "arm,smmu-v1", .data = (void *)ARM_SMMU_V1 }, { .compatible = "arm,smmu-v2", .data = (void *)ARM_SMMU_V2 }, { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 }, { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 }, { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 }, { }, }; MODULE_DEVICE_TABLE(of, arm_smmu_of_match); static int arm_smmu_device_dt_probe(struct platform_device *pdev) { const struct of_device_id *of_id; of_id = of_match_node(arm_smmu_of_match, dev->of_node); smmu->version = (enum arm_smmu_arch_version)of_id->data; ... if (smmu->version > ARM_SMMU_V1) { ... } } static struct platform_driver arm_smmu_driver = { .driver = { .name = "arm-smmu", .of_match_table = of_match_ptr(arm_smmu_of_match), }, .probe = arm_smmu_device_dt_probe, .remove = arm_smmu_device_remove, };
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:
static const struct xadc_ops xadc_zynq_ops = { .read = xadc_zynq_read_adc_reg, .write = xadc_zynq_write_adc_reg, .setup = xadc_zynq_setup, .get_dclk_rate = xadc_zynq_get_dclk_rate, .interrupt_handler = xadc_zynq_interrupt_handler, .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler, .update_alarm = xadc_zynq_update_alarm, }; static const struct of_device_id xadc_of_match_table[] = { { .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops }, { .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops }, { }, }; MODULE_DEVICE_TABLE(of, xadc_of_match_table); static int xadc_probe(struct platform_device *pdev) { const struct of_device_id *id; id = of_match_node(xadc_of_match_table, pdev->dev.of_node); ... indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc)); xadc = iio_priv(indio_dev); ... xadc->ops = id->data; ... ret = xadc->ops->setup(pdev, indio_dev, irq); ... } static struct platform_driver xadc_driver = { .probe = xadc_probe, .remove = xadc_remove, .driver = { .name = "xadc", .of_match_table = xadc_of_match_table, }, }; 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:
static const struct twl6030_gpadc_platform_data twl6030_pdata = { .iio_channels = twl6030_gpadc_iio_channels, .nchannels = TWL6030_GPADC_USED_CHANNELS, .ideal = twl6030_ideal, .start_conversion = twl6030_start_conversion, .channel_to_reg = twl6030_channel_to_reg, .calibrate = twl6030_calibration, }; static const struct of_device_id of_twl6030_match_tbl[] = { { .compatible = "ti,twl6030-gpadc", .data = &twl6030_pdata, }, { .compatible = "ti,twl6032-gpadc", .data = &twl6032_pdata, }, { /* end */ } }; static int twl6030_gpadc_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct twl6030_gpadc_platform_data *pdata; match = of_match_device(of_twl6030_match_tbl, dev); pdata = match->data; indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); gpadc = iio_priv(indio_dev); gpadc->pdata = pdata; platform_set_drvdata(pdev, indio_dev); ... ret = pdata->calibrate(gpadc); ... indio_dev->channels = pdata->iio_channels; indio_dev->num_channels = pdata->nchannels; }