diff mbox

[20/21] ASoC: codecs: Enable AB8500 CODEC for Device Tree

Message ID 1343298534-13611-21-git-send-email-lee.jones@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Lee Jones July 26, 2012, 10:28 a.m. UTC
We continue to allow the AB8500 CODEC to be registered via the AB8500
Multi Functional Device API, only this time we extract its configuration
from the Device Tree binary.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-core.c               |    1 +
 include/linux/mfd/abx500/ab8500-codec.h |    6 ++-
 sound/soc/codecs/ab8500-codec.c         |   79 +++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 2 deletions(-)

Comments

Mark Brown July 26, 2012, 11:50 a.m. UTC | #1
On Thu, Jul 26, 2012 at 11:28:53AM +0100, Lee Jones wrote:

>  drivers/mfd/ab8500-core.c               |    1 +
>  include/linux/mfd/abx500/ab8500-codec.h |    6 ++-
>  sound/soc/codecs/ab8500-codec.c         |   79 +++++++++++++++++++++++++++++++
>  3 files changed, 84 insertions(+), 2 deletions(-)

Yet again no binding documentation....

>  	{
>  		.name = "ab8500-codec",
> +		.of_compatible = "stericsson,ab8500-codec",
>  	},

Why are we doing this?  The MFD cells are a totally Linux specific
thing, there's no reason to represent them in the device tree unless
they're in some way reusable and the "ab8500-codec" name suggests that's
unlikely.  Just put the properties on the parent node and instantiate
the MFD cell as normal.

> +	/* Has a non-standard Vamic been requested? */
> +	if(of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))

Coding style.

> +	if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) {
> +		switch (value) {
> +		case 950 :
> +			codec->ear_cmv = EAR_CMV_0_95V;
> +			break;
> +		case 1100 :
> +			codec->ear_cmv = EAR_CMV_1_10V;
> +			break;
> +		case 1270 :
> +			codec->ear_cmv = EAR_CMV_1_27V;
> +			break;
> +		case 1580 :
> +			codec->ear_cmv = EAR_CMV_1_58V;
> +			break;
> +		default :
> +			codec->ear_cmv = EAR_CMV_UNKNOWN;
> +			dev_err(dev, "Unsuitable earpiece voltage found in DT\n");

The platform data code picks a default, can't the DT code do the same?
Lee Jones July 26, 2012, 2 p.m. UTC | #2
On 26/07/12 12:50, Mark Brown wrote:
> On Thu, Jul 26, 2012 at 11:28:53AM +0100, Lee Jones wrote:
>
>>   drivers/mfd/ab8500-core.c               |    1 +
>>   include/linux/mfd/abx500/ab8500-codec.h |    6 ++-
>>   sound/soc/codecs/ab8500-codec.c         |   79 +++++++++++++++++++++++++++++++
>>   3 files changed, 84 insertions(+), 2 deletions(-)
>
> Yet again no binding documentation....

RFC. ;)

I'll write the documentation when/if the properties are accepted.

>>   	{
>>   		.name = "ab8500-codec",
>> +		.of_compatible = "stericsson,ab8500-codec",
>>   	},
>
> Why are we doing this?  The MFD cells are a totally Linux specific
> thing, there's no reason to represent them in the device tree unless
> they're in some way reusable and the "ab8500-codec" name suggests that's
> unlikely.  Just put the properties on the parent node and instantiate
> the MFD cell as normal.
>
>> +	/* Has a non-standard Vamic been requested? */
>> +	if(of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))
>
> Coding style.

Missing space? Sorry, typo, I'll change.

>> +	if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) {
>> +		switch (value) {
>> +		case 950 :
>> +			codec->ear_cmv = EAR_CMV_0_95V;
>> +			break;
>> +		case 1100 :
>> +			codec->ear_cmv = EAR_CMV_1_10V;
>> +			break;
>> +		case 1270 :
>> +			codec->ear_cmv = EAR_CMV_1_27V;
>> +			break;
>> +		case 1580 :
>> +			codec->ear_cmv = EAR_CMV_1_58V;
>> +			break;
>> +		default :
>> +			codec->ear_cmv = EAR_CMV_UNKNOWN;
>> +			dev_err(dev, "Unsuitable earpiece voltage found in DT\n");
>
> The platform data code picks a default, can't the DT code do the same?

No, I don't think that it does? The original code returns -EINVAL unless 
a value is specified.

The original author is keen to have a clear error message in case users 
try to specify non-exact values. I'd rather we fail-out than use 
incorrect values which would be a great deal harder for a user to debug.
Lee Jones July 26, 2012, 2:15 p.m. UTC | #3
Sorry missed this:

>>   	{
>>   		.name = "ab8500-codec",
>> +		.of_compatible = "stericsson,ab8500-codec",
>>   	},
>
> Why are we doing this?  The MFD cells are a totally Linux specific
> thing, there's no reason to represent them in the device tree unless
> they're in some way reusable and the "ab8500-codec" name suggests that's
> unlikely.  Just put the properties on the parent node and instantiate
> the MFD cell as normal.

We have all of the AB8500 devices into the Device Tree to accurately 
represent the hardware. We will also be passing configuration 
information into the AB8500 Codec from Device Tree. The only reason 
we're still registering them using the MFD API is to overcome addressing 
issues encountered earlier. Each 'device' still belongs in the 'device' 
tree.

If we were to take this Device Tree and use it on something non-Linux, 
that OS will still need to know about each of the AB8500 devices and 
every associated configuration option. Only in Linux do we continue to 
register them though a different API, which doesn't affect any other OS.
Mark Brown July 26, 2012, 2:28 p.m. UTC | #4
On Thu, Jul 26, 2012 at 03:00:17PM +0100, Lee Jones wrote:
> On 26/07/12 12:50, Mark Brown wrote:

> >Yet again no binding documentation....

> RFC. ;)

> I'll write the documentation when/if the properties are accepted.

No, write the documentation.  It's way too much effort to reverse
engineer the bindings from the code.

> >>+		default :
> >>+			codec->ear_cmv = EAR_CMV_UNKNOWN;
> >>+			dev_err(dev, "Unsuitable earpiece voltage found in DT\n");

> >The platform data code picks a default, can't the DT code do the same?

> No, I don't think that it does? The original code returns -EINVAL
> unless a value is specified.

The code doesn't specify values for the enumeration so it ought to
default to EAR_CMV_0_95V if nothing is specified.

> The original author is keen to have a clear error message in case
> users try to specify non-exact values. I'd rather we fail-out than
> use incorrect values which would be a great deal harder for a user
> to debug.

By that argument all the properties should be mandatory but it's only
this one IIRC.
Mark Brown July 26, 2012, 2:43 p.m. UTC | #5
On Thu, Jul 26, 2012 at 03:15:01PM +0100, Lee Jones wrote:
> Sorry missed this:

> >Why are we doing this?  The MFD cells are a totally Linux specific
> >thing, there's no reason to represent them in the device tree unless
> >they're in some way reusable and the "ab8500-codec" name suggests that's
> >unlikely.  Just put the properties on the parent node and instantiate
> >the MFD cell as normal.

> We have all of the AB8500 devices into the Device Tree to accurately
> represent the hardware. We will also be passing configuration
> information into the AB8500 Codec from Device Tree. The only reason
> we're still registering them using the MFD API is to overcome
> addressing issues encountered earlier. Each 'device' still belongs
> in the 'device' tree.

The device here is the AB8500.  The fact that Linux chooses to represent
it as an MFD with a particular set of subdrivers is a Linux specific
decision and may well change over time.  For example it's likely that
we'll want to migrate the clocks out of the audio driver and into the
clock API when that becomes useful.  Similarly currently a lot of these
devices use ASoC level jack detection but that's going to move over to
extcon over time. 

There's no way you're going to be able to reuse this for anything that
isn't an AB8500, there's no abstraction of the SoC integration here.  If
you had clearly identifiable, repeatable IPs which you could reasonably
bind to a different bit of silicon then that'd be different but there's
nothing like that here.  We already know that the functionality covered
by the driver is going to be present simply by virtue of knowing that
there's an AB8500 and similarly there's no real way this driver could
ever be used without the core driver.  All the "device" in the device
tree is doing is serving as a container to place some of the DT
properties into, this needs to be separated out from the instantiation
of the Linux device driver.  There's nothing stopping the driver from
looking at the OF node of its parent here.

The goal here isn't just to copy the Linux device model and platform
data into device tree bindings, the device tree bindings need to think
about what the chip actually is so they can be reused by other OSs and
by future versions of Linux.

> If we were to take this Device Tree and use it on something
> non-Linux, that OS will still need to know about each of the AB8500
> devices and every associated configuration option. Only in Linux do
> we continue to register them though a different API, which doesn't
> affect any other OS.

Another OS might have a different idea about how it's going to split up
the chip which better fits with the models which that OS has for the
functions present on the device.  The reason this is a distinct device
in Linux is all to do with how Linux models the hardware.
Lee Jones July 26, 2012, 3:01 p.m. UTC | #6
On 26/07/12 15:28, Mark Brown wrote:
> On Thu, Jul 26, 2012 at 03:00:17PM +0100, Lee Jones wrote:
>> On 26/07/12 12:50, Mark Brown wrote:
>
>>> Yet again no binding documentation....
>
>> RFC. ;)
>
>> I'll write the documentation when/if the properties are accepted.
>
> No, write the documentation.  It's way too much effort to reverse
> engineer the bindings from the code.
>
>>>> +		default :
>>>> +			codec->ear_cmv = EAR_CMV_UNKNOWN;
>>>> +			dev_err(dev, "Unsuitable earpiece voltage found in DT\n");
>
>>> The platform data code picks a default, can't the DT code do the same?
>
>> No, I don't think that it does? The original code returns -EINVAL
>> unless a value is specified.
>
> The code doesn't specify values for the enumeration so it ought to
> default to EAR_CMV_0_95V if nothing is specified.

Ah, I see what you mean. I guess we could compromise and print a warning 
_and_ fall back to the 0th original emum.

>> The original author is keen to have a clear error message in case
>> users try to specify non-exact values. I'd rather we fail-out than
>> use incorrect values which would be a great deal harder for a user
>> to debug.
>
> By that argument all the properties should be mandatory but it's only
> this one IIRC.

This is the only value which the user can pick an obscure value, such as 
913, thinking they can pick 913mV. I'm happy to fall-back, as long as 
Ola is too.
Mark Brown July 26, 2012, 3:14 p.m. UTC | #7
On Thu, Jul 26, 2012 at 04:01:14PM +0100, Lee Jones wrote:

> This is the only value which the user can pick an obscure value,
> such as 913, thinking they can pick 913mV. I'm happy to fall-back,
> as long as Ola is too.

Erroring out if they pick an invalid value is fine, I'm more concerned
with the case where no property is supplied at all.
Lee Jones July 26, 2012, 3:17 p.m. UTC | #8
On 26/07/12 16:14, Mark Brown wrote:
> On Thu, Jul 26, 2012 at 04:01:14PM +0100, Lee Jones wrote:
>
>> This is the only value which the user can pick an obscure value,
>> such as 913, thinking they can pick 913mV. I'm happy to fall-back,
>> as long as Ola is too.
>
> Erroring out if they pick an invalid value is fine, I'm more concerned
> with the case where no property is supplied at all.

Hmmm... I'll have a think.
Lee Jones July 26, 2012, 3:19 p.m. UTC | #9
On 26/07/12 15:43, Mark Brown wrote:
> On Thu, Jul 26, 2012 at 03:15:01PM +0100, Lee Jones wrote:
>> Sorry missed this:
>
>>> Why are we doing this?  The MFD cells are a totally Linux specific
>>> thing, there's no reason to represent them in the device tree unless
>>> they're in some way reusable and the "ab8500-codec" name suggests that's
>>> unlikely.  Just put the properties on the parent node and instantiate
>>> the MFD cell as normal.
>
>> We have all of the AB8500 devices into the Device Tree to accurately
>> represent the hardware. We will also be passing configuration
>> information into the AB8500 Codec from Device Tree. The only reason
>> we're still registering them using the MFD API is to overcome
>> addressing issues encountered earlier. Each 'device' still belongs
>> in the 'device' tree.
>
> The device here is the AB8500.  The fact that Linux chooses to represent
> it as an MFD with a particular set of subdrivers is a Linux specific
> decision and may well change over time.  For example it's likely that
> we'll want to migrate the clocks out of the audio driver and into the
> clock API when that becomes useful.  Similarly currently a lot of these
> devices use ASoC level jack detection but that's going to move over to
> extcon over time.
>
> There's no way you're going to be able to reuse this for anything that
> isn't an AB8500, there's no abstraction of the SoC integration here.  If
> you had clearly identifiable, repeatable IPs which you could reasonably
> bind to a different bit of silicon then that'd be different but there's
> nothing like that here.  We already know that the functionality covered
> by the driver is going to be present simply by virtue of knowing that
> there's an AB8500 and similarly there's no real way this driver could
> ever be used without the core driver.  All the "device" in the device
> tree is doing is serving as a container to place some of the DT
> properties into, this needs to be separated out from the instantiation
> of the Linux device driver.  There's nothing stopping the driver from
> looking at the OF node of its parent here.
>
> The goal here isn't just to copy the Linux device model and platform
> data into device tree bindings, the device tree bindings need to think
> about what the chip actually is so they can be reused by other OSs and
> by future versions of Linux.
>
>> If we were to take this Device Tree and use it on something
>> non-Linux, that OS will still need to know about each of the AB8500
>> devices and every associated configuration option. Only in Linux do
>> we continue to register them though a different API, which doesn't
>> affect any other OS.
>
> Another OS might have a different idea about how it's going to split up
> the chip which better fits with the models which that OS has for the
> functions present on the device.  The reason this is a distinct device
> in Linux is all to do with how Linux models the hardware.

Okay, so your suggestion is to strip out all of the sub-devices under 
the AB8500. It's doable, but will take some restructuring and thinking 
about. This is a job for another day. I think it's okay to continue with 
the current semantics for the time-being. The line we're discussing does 
need to be split out though. I didn't mean to merge it in with the ASoC 
stuff.
Mark Brown July 26, 2012, 3:24 p.m. UTC | #10
On Thu, Jul 26, 2012 at 04:19:33PM +0100, Lee Jones wrote:

> Okay, so your suggestion is to strip out all of the sub-devices
> under the AB8500. It's doable, but will take some restructuring and
> thinking about. This is a job for another day. I think it's okay to
> continue with the current semantics for the time-being. The line
> we're discussing does need to be split out though. I didn't mean to
> merge it in with the ASoC stuff.

Yes, well any that aren't reusable at any rate.  If you could relocate
the device into another SoC integation that'd be different.
diff mbox

Patch

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 626b4ec..0c5b70f 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1076,6 +1076,7 @@  static struct mfd_cell __devinitdata ab8500_devs[] = {
 	},
 	{
 		.name = "ab8500-codec",
+		.of_compatible = "stericsson,ab8500-codec",
 	},
 };
 
diff --git a/include/linux/mfd/abx500/ab8500-codec.h b/include/linux/mfd/abx500/ab8500-codec.h
index dc65292..d707941 100644
--- a/include/linux/mfd/abx500/ab8500-codec.h
+++ b/include/linux/mfd/abx500/ab8500-codec.h
@@ -23,7 +23,8 @@  enum amic_type {
 /* Mic-biases */
 enum amic_micbias {
 	AMIC_MICBIAS_VAMIC1,
-	AMIC_MICBIAS_VAMIC2
+	AMIC_MICBIAS_VAMIC2,
+	AMIC_MICBIAS_UNKNOWN
 };
 
 /* Bias-voltage */
@@ -31,7 +32,8 @@  enum ear_cm_voltage {
 	EAR_CMV_0_95V,
 	EAR_CMV_1_10V,
 	EAR_CMV_1_27V,
-	EAR_CMV_1_58V
+	EAR_CMV_1_58V,
+	EAR_CMV_UNKNOWN
 };
 
 /* Analog microphone settings */
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 3c79592..e3ae9f5 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -34,6 +34,7 @@ 
 #include <linux/mfd/abx500/ab8500-sysctrl.h>
 #include <linux/mfd/abx500/ab8500-codec.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -2394,9 +2395,62 @@  struct snd_soc_dai_driver ab8500_codec_dai[] = {
 	}
 };
 
+static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
+				struct ab8500_codec_platform_data *codec)
+{
+	u32 value;
+
+	if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL))
+		codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED;
+	else
+		codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL;
+
+	if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL))
+		codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED;
+	else
+		codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL;
+
+	/* Has a non-standard Vamic been requested? */
+	if(of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))
+		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2;
+	else
+		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1;
+
+	if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL))
+		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2;
+	else
+		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1;
+
+	if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL))
+		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1;
+	else
+		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2;
+
+	if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) {
+		switch (value) {
+		case 950 :
+			codec->ear_cmv = EAR_CMV_0_95V;
+			break;
+		case 1100 :
+			codec->ear_cmv = EAR_CMV_1_10V;
+			break;
+		case 1270 :
+			codec->ear_cmv = EAR_CMV_1_27V;
+			break;
+		case 1580 :
+			codec->ear_cmv = EAR_CMV_1_58V;
+			break;
+		default :
+			codec->ear_cmv = EAR_CMV_UNKNOWN;
+			dev_err(dev, "Unsuitable earpiece voltage found in DT\n");
+		}
+	}
+}
+
 static int ab8500_codec_probe(struct snd_soc_codec *codec)
 {
 	struct device *dev = codec->dev;
+	struct device_node *np = dev->of_node;
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
 	struct ab8500_platform_data *pdata;
 	struct filter_control *fc;
@@ -2406,6 +2460,31 @@  static int ab8500_codec_probe(struct snd_soc_codec *codec)
 
 	/* Setup AB8500 according to board-settings */
 	pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent);
+
+	if (np) {
+		if (!pdata)
+			pdata = devm_kzalloc(dev,
+					sizeof(struct ab8500_platform_data),
+					GFP_KERNEL);
+
+		if (!pdata->codec)
+			pdata->codec
+				= devm_kzalloc(dev,
+					sizeof(struct ab8500_codec_platform_data),
+					GFP_KERNEL);
+
+		if (!(pdata && pdata->codec))
+			return -ENOMEM;
+
+		ab8500_codec_of_probe(dev, np, pdata->codec);
+
+	} else {
+		if (!(pdata && pdata->codec)) {
+			dev_err(dev, "No codec platform data or DT found\n");
+			return -EINVAL;
+		}
+	}
+
 	status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
 	if (status < 0) {
 		pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);