From 04561eacaa6ccd1988e468cdcbf4acc475ae2221 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 23 May 2013 15:46:05 +0200 Subject: ASoC: codecs: adau1701: add DT bindings Apart from pure matching, the bindings also support setting the the reset gpio line. Signed-off-by: Daniel Mack Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/adi,adau1701.txt | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,adau1701.txt (limited to 'Documentation/devicetree/bindings/sound/adi,adau1701.txt') diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt new file mode 100644 index 000000000000..3afeda77b5b9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau1701.txt @@ -0,0 +1,23 @@ +Analog Devices ADAU1701 + +Required properties: + + - compatible: Should contain "adi,adau1701" + - reg: The i2c address. Value depends on the state of ADDR0 + and ADDR1, as wired in hardware. + +Optional properties: + + - reset-gpio: A GPIO spec to define which pin is connected to the + chip's !RESET pin. If specified, the driver will + assert a hardware reset at probe time. + +Examples: + + i2c_bus { + adau1701@34 { + compatible = "adi,adau1701"; + reg = <0x34>; + reset-gpio = <&gpio 23 0>; + }; + }; -- cgit v1.2.3 From 2352d4bf43b105ec2da5f43211db4a4c9bf34d4e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 24 Jun 2013 16:31:30 +0200 Subject: ASoC: adau1701: allow configuration of PLL mode pins The ADAU1701 has 2 hardware pins to configure the PLL mode in accordance to the MCLK-to-LRCLK ratio. These pins have to be stable before the chip is released from reset, and a full reset cycle, including a new firmware download is needed whenever they change. This patch adds GPIO properties to the DT bindings of the Codec, and implements makes the set_sysclk memorize the configured sysclk. Because the run-time parameters are unknown at probe time, the first firmware download is postponed to the first hw_params call, when the driver can determine the mclk/lrclk divider. Subsequent downloads are only issued when the divider configuration changes. Signed-off-by: Daniel Mack Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/adi,adau1701.txt | 6 ++ sound/soc/codecs/adau1701.c | 105 +++++++++++++++++++-- 2 files changed, 104 insertions(+), 7 deletions(-) (limited to 'Documentation/devicetree/bindings/sound/adi,adau1701.txt') diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt index 3afeda77b5b9..a9fbed1be40e 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau1701.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau1701.txt @@ -11,6 +11,11 @@ Optional properties: - reset-gpio: A GPIO spec to define which pin is connected to the chip's !RESET pin. If specified, the driver will assert a hardware reset at probe time. + - adi,pll-mode-gpios: An array of two GPIO specs to describe the GPIOs + the ADAU's PLL config pins are connected to. + The state of the pins are set according to the + configured clock divider on ASoC side before the + firmware is loaded. Examples: @@ -19,5 +24,6 @@ Examples: compatible = "adi,adau1701"; reg = <0x34>; reset-gpio = <&gpio 23 0>; + adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>; }; }; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 997fc3b881fe..770d90ee5f92 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -87,11 +87,16 @@ #define ADAU1701_OSCIPOW_OPD 0x04 #define ADAU1701_DACSET_DACINIT 1 +#define ADAU1707_CLKDIV_UNSET (-1UL) + #define ADAU1701_FIRMWARE "adau1701.bin" struct adau1701 { int gpio_nreset; + int gpio_pll_mode[2]; unsigned int dai_fmt; + unsigned int pll_clkdiv; + unsigned int sysclk; }; static const struct snd_kcontrol_new adau1701_controls[] = { @@ -184,12 +189,38 @@ static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) return value; } -static int adau1701_reset(struct snd_soc_codec *codec) +static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) { struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); struct i2c_client *client = to_i2c_client(codec->dev); int ret; + if (clkdiv != ADAU1707_CLKDIV_UNSET && + gpio_is_valid(adau1701->gpio_pll_mode[0]) && + gpio_is_valid(adau1701->gpio_pll_mode[1])) { + switch (clkdiv) { + case 64: + gpio_set_value(adau1701->gpio_pll_mode[0], 0); + gpio_set_value(adau1701->gpio_pll_mode[1], 0); + break; + case 256: + gpio_set_value(adau1701->gpio_pll_mode[0], 0); + gpio_set_value(adau1701->gpio_pll_mode[1], 1); + break; + case 384: + gpio_set_value(adau1701->gpio_pll_mode[0], 1); + gpio_set_value(adau1701->gpio_pll_mode[1], 0); + break; + case 0: /* fallback */ + case 512: + gpio_set_value(adau1701->gpio_pll_mode[0], 1); + gpio_set_value(adau1701->gpio_pll_mode[1], 1); + break; + } + } + + adau1701->pll_clkdiv = clkdiv; + if (gpio_is_valid(adau1701->gpio_nreset)) { gpio_set_value(adau1701->gpio_nreset, 0); /* minimum reset time is 20ns */ @@ -199,10 +230,16 @@ static int adau1701_reset(struct snd_soc_codec *codec) mdelay(85); } - ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); - if (ret) { - dev_warn(codec->dev, "Failed to load firmware\n"); - return ret; + /* + * Postpone the firmware download to a point in time when we + * know the correct PLL setup + */ + if (clkdiv != ADAU1707_CLKDIV_UNSET) { + ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); + if (ret) { + dev_warn(codec->dev, "Failed to load firmware\n"); + return ret; + } } snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); @@ -285,8 +322,22 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + unsigned int clkdiv = adau1701->sysclk / params_rate(params); snd_pcm_format_t format; unsigned int val; + int ret; + + /* + * If the mclk/lrclk ratio changes, the chip needs updated PLL + * mode GPIO settings, and a full reset cycle, including a new + * firmware upload. + */ + if (clkdiv != adau1701->pll_clkdiv) { + ret = adau1701_reset(codec, clkdiv); + if (ret < 0) + return ret; + } switch (params_rate(params)) { case 192000: @@ -429,6 +480,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { unsigned int val; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); switch (clk_id) { case ADAU1701_CLK_SRC_OSC: @@ -442,6 +494,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, } snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); + adau1701->sysclk = freq; return 0; } @@ -489,11 +542,21 @@ MODULE_DEVICE_TABLE(of, adau1701_dt_ids); static int adau1701_probe(struct snd_soc_codec *codec) { int ret; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); codec->control_data = to_i2c_client(codec->dev); - ret = adau1701_reset(codec); - if (ret) + /* + * Let the pll_clkdiv variable default to something that won't happen + * at runtime. That way, we can postpone the firmware download from + * adau1701_reset() to a point in time when we know the correct PLL + * mode parameters. + */ + adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; + + /* initalize with pre-configured pll mode settings */ + ret = adau1701_reset(codec, adau1701->pll_clkdiv); + if (ret < 0) return ret; return 0; @@ -526,6 +589,7 @@ static int adau1701_i2c_probe(struct i2c_client *client, struct adau1701 *adau1701; struct device *dev = &client->dev; int gpio_nreset = -EINVAL; + int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; int ret; adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); @@ -536,6 +600,16 @@ static int adau1701_i2c_probe(struct i2c_client *client, gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); if (gpio_nreset < 0 && gpio_nreset != -ENOENT) return gpio_nreset; + + gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, + "adi,pll-mode-gpios", 0); + if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) + return gpio_pll_mode[0]; + + gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, + "adi,pll-mode-gpios", 1); + if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) + return gpio_pll_mode[1]; } if (gpio_is_valid(gpio_nreset)) { @@ -545,7 +619,24 @@ static int adau1701_i2c_probe(struct i2c_client *client, return ret; } + if (gpio_is_valid(gpio_pll_mode[0]) && + gpio_is_valid(gpio_pll_mode[1])) { + ret = devm_gpio_request_one(dev, gpio_pll_mode[0], + GPIOF_OUT_INIT_LOW, + "ADAU1701 PLL mode 0"); + if (ret < 0) + return ret; + + ret = devm_gpio_request_one(dev, gpio_pll_mode[1], + GPIOF_OUT_INIT_LOW, + "ADAU1701 PLL mode 1"); + if (ret < 0) + return ret; + } + adau1701->gpio_nreset = gpio_nreset; + adau1701->gpio_pll_mode[0] = gpio_pll_mode[0]; + adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; i2c_set_clientdata(client, adau1701); ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, -- cgit v1.2.3 From 97d0a868450d08fae0db3f53459852901c6e2f4f Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 24 Jun 2013 16:31:32 +0200 Subject: ASoC: adau1701: add support for pin muxing The ADAU1701 has 12 pins that can be configured depending on the system configuration. Allow settting the corresponding registers from DT. Signed-off-by: Daniel Mack Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/adi,adau1701.txt | 6 ++++ sound/soc/codecs/adau1701.c | 32 ++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'Documentation/devicetree/bindings/sound/adi,adau1701.txt') diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt index a9fbed1be40e..547a49b56a62 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau1701.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau1701.txt @@ -16,6 +16,10 @@ Optional properties: The state of the pins are set according to the configured clock divider on ASoC side before the firmware is loaded. + - adi,pin-config: An array of 12 numerical values selecting one of the + pin configurations as described in the datasheet, + table 53. Note that the value of this property has + to be prefixed with '/bits/ 8'. Examples: @@ -25,5 +29,7 @@ Examples: reg = <0x34>; reset-gpio = <&gpio 23 0>; adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>; + adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4 + 0x4 0x4 0x4 0x4 0x4 0x4>; }; }; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 881bab4a65aa..0e250f118c0e 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -29,6 +29,9 @@ #define ADAU1701_SEROCTL 0x081e #define ADAU1701_SERICTL 0x081f +#define ADAU1701_AUXNPOW 0x0822 +#define ADAU1701_PINCONF_0 0x0820 +#define ADAU1701_PINCONF_1 0x0821 #define ADAU1701_AUXNPOW 0x0822 #define ADAU1701_OSCIPOW 0x0826 @@ -99,6 +102,7 @@ struct adau1701 { unsigned int pll_clkdiv; unsigned int sysclk; struct regmap *regmap; + u8 pin_config[12]; }; static const struct snd_kcontrol_new adau1701_controls[] = { @@ -134,6 +138,9 @@ static unsigned int adau1701_register_size(struct device *dev, unsigned int reg) { switch (reg) { + case ADAU1701_PINCONF_0: + case ADAU1701_PINCONF_1: + return 3; case ADAU1701_DSPCTRL: case ADAU1701_SEROCTL: case ADAU1701_AUXNPOW: @@ -164,7 +171,7 @@ static int adau1701_reg_write(void *context, unsigned int reg, struct i2c_client *client = context; unsigned int i; unsigned int size; - uint8_t buf[4]; + uint8_t buf[5]; int ret; size = adau1701_register_size(&client->dev, reg); @@ -584,7 +591,8 @@ MODULE_DEVICE_TABLE(of, adau1701_dt_ids); static int adau1701_probe(struct snd_soc_codec *codec) { - int ret; + int i, ret; + unsigned int val; struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); codec->control_data = to_i2c_client(codec->dev); @@ -602,6 +610,19 @@ static int adau1701_probe(struct snd_soc_codec *codec) if (ret < 0) return ret; + /* set up pin config */ + val = 0; + for (i = 0; i < 6; i++) + val |= adau1701->pin_config[i] << (i * 4); + + regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val); + + val = 0; + for (i = 0; i < 6; i++) + val |= adau1701->pin_config[i + 6] << (i * 4); + + regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val); + return 0; } @@ -662,6 +683,13 @@ static int adau1701_i2c_probe(struct i2c_client *client, "adi,pll-mode-gpios", 1); if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) return gpio_pll_mode[1]; + + of_property_read_u32(dev->of_node, "adi,pll-clkdiv", + &adau1701->pll_clkdiv); + + of_property_read_u8_array(dev->of_node, "adi,pin-config", + adau1701->pin_config, + ARRAY_SIZE(adau1701->pin_config)); } if (gpio_is_valid(gpio_nreset)) { -- cgit v1.2.3