diff --git a/Documentation/devicetree/bindings/sound/ac97-bus.txt b/Documentation/devicetree/bindings/sound/ac97-bus.txt new file mode 100644 index 000000000000..103c428f2595 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ac97-bus.txt @@ -0,0 +1,32 @@ +Generic AC97 Device Properties + +This documents describes the devicetree bindings for an ac97 controller child +node describing ac97 codecs. + +Required properties: +-compatible : Must be "ac97,vendor_id1,vendor_id2 + The ids shall be the 4 characters hexadecimal encoding, such as + given by "%04x" formatting of printf +-reg : Must be the ac97 codec number, between 0 and 3 + +Example: +ac97: sound@40500000 { + compatible = "marvell,pxa270-ac97"; + reg = < 0x40500000 0x1000 >; + interrupts = <14>; + reset-gpios = <&gpio 95 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = < &pinctrl_ac97_default >; + clocks = <&clks CLK_AC97>, <&clks CLK_AC97CONF>; + clock-names = "AC97CLK", "AC97CONFCLK"; + + #address-cells = <1>; + #size-cells = <0>; + audio-codec@0 { + reg = <0>; + compatible = "ac97,574d,4c13"; + clocks = <&fixed_wm9713_clock>; + clock-names = "ac97_clk"; + } +}; diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 31f858eceffc..7a0dfca03a57 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,27 @@ ac97_codec_find(struct ac97_controller *ac97_ctrl, unsigned int codec_num) return ac97_ctrl->codecs[codec_num]; } +static struct device_node * +ac97_of_get_child_device(struct ac97_controller *ac97_ctrl, int idx, + unsigned int vendor_id) +{ + struct device_node *node; + u32 reg; + char compat[] = "ac97,0000,0000"; + + snprintf(compat, sizeof(compat), "ac97,%04x,%04x", + vendor_id >> 16, vendor_id & 0xffff); + + for_each_child_of_node(ac97_ctrl->parent->of_node, node) { + if ((idx != of_property_read_u32(node, "reg", ®)) || + !of_device_is_compatible(node, compat)) + continue; + return of_node_get(node); + } + + return NULL; +} + static void ac97_codec_release(struct device *dev) { struct ac97_codec_device *adev; @@ -76,6 +98,7 @@ static void ac97_codec_release(struct device *dev) adev = to_ac97_device(dev); ac97_ctrl = adev->ac97_ctrl; ac97_ctrl->codecs[adev->num] = NULL; + of_node_put(dev->of_node); kfree(adev); } @@ -98,6 +121,8 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx, device_initialize(&codec->dev); dev_set_name(&codec->dev, "%s:%u", dev_name(ac97_ctrl->parent), idx); + codec->dev.of_node = ac97_of_get_child_device(ac97_ctrl, idx, + vendor_id); ret = device_add(&codec->dev); if (ret) @@ -105,6 +130,7 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx, return 0; err_free_codec: + of_node_put(codec->dev.of_node); put_device(&codec->dev); kfree(codec); ac97_ctrl->codecs[idx] = NULL;