scripts: dts: Change 'child/parent: bus: ...' to 'child/parent-bus:'

Instead of

    child:
        bus: foo

    parent:
        bus: bar

, have

    child-bus: foo

    parent-bus: bar

'bus' is the only key that ever appears under 'child' and 'parent'.

Support the old keys for backwards compatibility, with a deprecation
warning if they're used.

Also add 'child/parent-bus' tests to the edtlib test suite. It was
untested before.

I also considered putting more stuff under 'child' and 'parent', but
there's not much point when there's just a few keys I think. Top-level
stuff is cleaner and easier to read.

I'm planning to add a 'child-binding' key a bit later (like 'sub-node',
but more flexible), and child-* is consistent with that.

Also add an unrelated test-bindings/grandchild-3.yaml that was
accidentally left out earlier.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
This commit is contained in:
Ulf Magnusson 2019-09-16 16:42:18 +02:00 committed by Kumar Gala
commit 1ebe945643
25 changed files with 156 additions and 54 deletions

View file

@ -46,19 +46,19 @@ compatible: "manufacturer,device"
# 'required: true' is always respected.
include: other.yaml # or [other1.yaml, other2.yaml]
# If the node describes a bus, then the bus type should be given, like below
child:
bus: <string describing bus type, e.g. "i2c">
# If the node describes a bus, then the bus type should be given, like below.
# The name has "child" in it since it describes the bus children of the node
# appear on.
child-bus: <string describing bus type, e.g. "i2c">
# If the node appears on a bus, then the bus type should be given, like below.
#
# When looking for a binding for a node, the code checks if the binding for the
# parent node contains 'child: bus: <bus type>'. If it does, then only bindings
# with a matching 'parent: bus: <bus type>' are considered. This allows the
# same type of device to have different bindings depending on what bus it
# appears on.
parent:
bus: <string describing bus type, e.g. "i2c">
# parent node contains 'child-bus: <bus type>'. If it does, then only bindings
# with a matching 'parent-bus: <bus type>' are considered. This allows the same
# type of device to have different bindings depending on what bus it appears
# on.
parent-bus: <string describing bus type, e.g. "i2c">
# 'sub-node' is used to simplify cases where a node has children that can all
# use the same binding. The contents of 'sub-node' becomes the binding for each

View file

@ -11,8 +11,7 @@ compatible: "zephyr,bt-hci-spi-slave"
include: base.yaml
parent:
bus: spi
parent-bus: spi
properties:
irq-gpios:

View file

@ -2,8 +2,7 @@
include: base.yaml
child:
bus: can
child-bus: can
properties:
"#address-cells":

View file

@ -5,8 +5,7 @@
include: base.yaml
parent:
bus: can
parent-bus: can
properties:
reg:

View file

@ -5,8 +5,7 @@
include: base.yaml
child:
bus: espi
child-bus: espi
properties:
label:

View file

@ -6,8 +6,7 @@ compatible: "holtek,ht16k33-keyscan"
include: base.yaml
parent:
bus: ht16k33
parent-bus: ht16k33
properties:
reg:

View file

@ -5,8 +5,7 @@
include: base.yaml
child:
bus: i2c
child-bus: i2c
properties:
"#address-cells":

View file

@ -5,8 +5,7 @@
include: base.yaml
parent:
bus: i2c
parent-bus: i2c
properties:
reg:

View file

@ -5,8 +5,7 @@
include: base.yaml
child:
bus: i2s
child-bus: i2s
properties:
"#address-cells":

View file

@ -5,8 +5,7 @@
include: base.yaml
parent:
bus: i2s
parent-bus: i2s
properties:
reg:

View file

@ -6,8 +6,7 @@ compatible: "holtek,ht16k33"
include: i2c-device.yaml
child:
bus: ht16k33
child-bus: ht16k33
properties:
"#address-cells":

View file

@ -2,8 +2,7 @@
include: base.yaml
child:
bus: uart
child-bus: uart
properties:
clock-frequency:

View file

@ -5,8 +5,7 @@
include: base.yaml
parent:
bus: uart
parent-bus: uart
properties:
label:

View file

@ -5,8 +5,7 @@
include: base.yaml
child:
bus: spi
child-bus: spi
properties:
clock-frequency:

View file

@ -5,8 +5,7 @@
include: base.yaml
parent:
bus: spi
parent-bus: spi
properties:
reg:

View file

@ -580,15 +580,25 @@ class Device:
self.description = None
def _bus_from_parent_binding(self):
# _init_binding() helper. Returns the bus specified by
# 'child: bus: ...' in the parent binding, or None if missing.
# _init_binding() helper. Returns the bus specified by 'child-bus: ...'
# in the parent binding (or the legacy 'child: bus: ...'), or None if
# missing.
if not self.parent:
return None
binding = self.parent._binding
if binding and "child" in binding:
return binding["child"].get("bus")
if not binding:
return None
if "child-bus" in binding:
return binding["child-bus"]
# Legacy key
if "child" in binding:
# _check_binding() has checked that the "bus" key exists
return binding["child"]["bus"]
return None
def _init_props(self):
@ -1307,12 +1317,20 @@ def _binding_compat(binding, binding_path):
def _binding_bus(binding):
# Returns the bus specified in 'binding' (the bus the device described by
# 'binding' is on), e.g. "i2c", or None if 'binding' is None or doesn't
# specify a bus
# Returns the bus specified by 'parent-bus: ...' in the binding (or the
# legacy 'parent: bus: ...'), or None if missing
if not binding:
return None
if "parent-bus" in binding:
return binding["parent-bus"]
# Legacy key
if "parent" in binding:
# _check_binding() has checked that the "bus" key exists
return binding["parent"]["bus"]
if binding and "parent" in binding:
return binding["parent"].get("bus")
return None
@ -1421,7 +1439,7 @@ def _check_binding(binding, binding_path):
.format(prop, binding_path))
ok_top = {"title", "description", "compatible", "properties", "#cells",
"parent", "child", "sub-node"}
"parent-bus", "child-bus", "parent", "child", "sub-node"}
for prop in binding:
if prop not in ok_top:
@ -1429,8 +1447,20 @@ def _check_binding(binding, binding_path):
.format(prop, binding_path, ", ".join(ok_top)))
for pc in "parent", "child":
# 'parent/child-bus:'
bus_key = pc + "-bus"
if bus_key in binding and \
not isinstance(binding[bus_key], str):
_warn("malformed '{}:' value in {}, expected string"
.format(bus_key, binding_path))
# Legacy 'child/parent: bus: ...' keys
if pc in binding:
# Just 'bus:' is expected at the moment
_warn("'{0}: bus: ...' in {1} is deprecated and will be removed - "
"please use a top-level '{0}-bus:' key instead (see "
"binding-template.yaml)".format(pc, binding_path))
# Just 'bus:' is expected
if binding[pc].keys() != {"bus"}:
_err("expected (just) 'bus:' in '{}:' in {}"
.format(pc, binding_path))

View file

@ -317,6 +317,11 @@ def get_binding(node_path):
return parent_binding['sub-node']
# look for a bus-specific binding
if 'child-bus' in parent_binding:
bus = parent_binding['child-bus']
return bus_bindings[bus][compat]
if 'child' in parent_binding and 'bus' in parent_binding['child']:
bus = parent_binding['child']['bus']
return bus_bindings[bus][compat]

View file

@ -65,7 +65,8 @@ def generate_prop_defines(node_path, prop):
# named 'prop' on the device tree node at 'node_path'
binding = get_binding(node_path)
if 'parent' in binding and 'bus' in binding['parent']:
if 'parent-bus' in binding or \
'parent' in binding and 'bus' in binding['parent']:
# If the binding specifies a parent for the node, then include the
# parent in the #define's generated for the properties
parent_path = get_parent_path(node_path)
@ -154,7 +155,8 @@ def generate_bus_defines(node_path):
# bus: ...
binding = get_binding(node_path)
if not ('parent' in binding and 'bus' in binding['parent']):
if not ('parent-bus' in binding or
'parent' in binding and 'bus' in binding['parent']):
return
parent_path = get_parent_path(node_path)
@ -162,17 +164,24 @@ def generate_bus_defines(node_path):
# Check that parent has matching child bus value
try:
parent_binding = get_binding(parent_path)
parent_bus = parent_binding['child']['bus']
if 'child-bus' in parent_binding:
parent_bus = parent_binding['child-bus']
else:
parent_bus = parent_binding['child']['bus']
except (KeyError, TypeError):
raise Exception("{0} defines parent {1} as bus master, but {1} is not "
"configured as bus master in binding"
.format(node_path, parent_path))
if parent_bus != binding['parent']['bus']:
if 'parent-bus' in binding:
bus = binding['parent-bus']
else:
bus = binding['parent']['bus']
if parent_bus != bus:
raise Exception("{0} defines parent {1} as {2} bus master, but {1} is "
"configured as {3} bus master"
.format(node_path, parent_path,
binding['parent']['bus'], parent_bus))
.format(node_path, parent_path, bus, parent_bus))
# Generate *_BUS_NAME #define
extract_bus_name(
@ -358,6 +367,9 @@ def load_bindings(root, binding_dirs):
if compat not in compats:
compats.append(compat)
if 'parent-bus' in binding:
bus_to_binding[binding['parent-bus']][compat] = binding
if 'parent' in binding:
bus_to_binding[binding['parent']['bus']][compat] = binding

View file

@ -0,0 +1,8 @@
# SPDX-License-Identifier: BSD-3-Clause
title: Bar bus controller
description: Bar bus controller
compatible: "bar-bus"
child-bus: "bar"

View file

@ -0,0 +1,8 @@
# SPDX-License-Identifier: BSD-3-Clause
title: Device on bar bus
description: Device on bar bus
compatible: "on-bus"
parent-bus: "bar"

View file

@ -0,0 +1,8 @@
# SPDX-License-Identifier: BSD-3-Clause
title: Device on foo bus
description: Device on foo bus
compatible: "on-bus"
parent-bus: "foo"

View file

@ -0,0 +1,8 @@
# SPDX-License-Identifier: BSD-3-Clause
title: Foo bus controller
description: Foo bus controller
compatible: "foo-bus"
child-bus: "foo"

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: BSD-3-Clause
properties:
qaz:
required: true
type: int

View file

@ -318,6 +318,27 @@
default-not-used = <234>;
};
//
// For testing 'child-bus:' and 'parent-bus:'
//
buses {
// The nodes below will map to different bindings since they
// appear on different buses
foo-bus {
compatible = "foo-bus";
node {
compatible = "on-bus";
};
};
bar-bus {
compatible = "bar-bus";
node {
compatible = "on-bus";
};
};
};
//
// Parent with 'sub-node:' in binding
//

View file

@ -105,6 +105,16 @@ def run():
verify_streq(edt.get_dev("/binding-include").props,
"{'foo': <Property, name: foo, type: int, value: 0>, 'bar': <Property, name: bar, type: int, value: 1>, 'baz': <Property, name: baz, type: int, value: 2>, 'qaz': <Property, name: qaz, type: int, value: 3>}")
#
# Test 'child/parent-bus:'
#
verify_streq(edt.get_dev("/buses/foo-bus/node").binding_path,
"test-bindings/device-on-foo-bus.yaml")
verify_streq(edt.get_dev("/buses/bar-bus/node").binding_path,
"test-bindings/device-on-bar-bus.yaml")
#
# Test 'sub-node:' in binding
#