From: Pierluigi Passaro <pierluigi.p@xxxxxxxxxxxxx> The platform_data structure is not populated when using device trees. This patch adds optional dts properties to allow populating it: - gpio-cfg - mic-cfg - num-drc-cfgs - drc-cfg-regs - drc-cfg-names - num-retune-mobile-cfgs - retune-mobile-cfg-regs - retune-mobile-cfg-names - retune-mobile-cfg-rates Signed-off-by: Pierluigi Passaro <pierluigi.p@xxxxxxxxxxxxx> Signed-off-by: Alifer Moraes <alifer.m@xxxxxxxxxxxxx> --- .../devicetree/bindings/sound/wm8904.txt | 53 ++++++++ sound/soc/codecs/wm8904.c | 113 +++++++++++++++++- 2 files changed, 164 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/wm8904.txt b/Documentation/devicetree/bindings/sound/wm8904.txt index 66bf261423b9..e3bfd3ec2905 100644 --- a/Documentation/devicetree/bindings/sound/wm8904.txt +++ b/Documentation/devicetree/bindings/sound/wm8904.txt @@ -9,6 +9,40 @@ Required properties: - clocks: reference to <Documentation/devicetree/bindings/clock/clock-bindings.txt> +Optional properties: + + - gpio-cfg: Default registers value for R121/122/123/124 (GPIO Control). + The list must be 4 entries long. If absent, the registers are set to 0. + If any entry has the value 0xffff, the related register won't be set. + + - mic-cfg: Default registers value for R6/R7 (Mic Bias Control). + The list must be 2 entries long. If absent, the registers are set to 0. + + - num-drc-cfgs: Number of available DRC modes from drc-cfg-regs property + + - drc-cfg-regs: Default registers value for R40/41/42/43 (DRC) + The list must be (4 x num-drc-cfgs) entries long. + If absent or incomplete, DRC is disabled. + + - drc-cfg-names: List of strings for the available DRC modes. + The list must be (num-drc-cfgs) entries long. + If absent or incomplete, DRC is disabled. + + - num-retune-mobile-cfgs: Number of retune modes available from + retune-mobile-cfg-regs property + + - retune-mobile-cfg-regs: Default registers value for R134/.../157 (EQ) + The list must be (24 x num-retune-mobile-cfgs) entries long. + If absent or incomplete, retune is disabled. + + - retune-mobile-cfg-names: List of strings for the available retune modes. + The list must be (num-retune-mobile-cfgs) entries long. + If absent or incomplete, retune is disabled. + + - retune-mobile-cfg-rates: List of rates for the available retune modes. + The list must be (num-retune-mobile-cfgs) entries long. + If absent or incomplete, retune is disabled. + Pins on the device (for linking into audio routes): * IN1L @@ -30,4 +64,23 @@ codec: wm8904@1a { reg = <0x1a>; clocks = <&pck0>; clock-names = "mclk"; + num-drc-cfgs = <5>; + drc-cfg-names = "default", "peaklimiter", "tradition", "soft", "music"; + drc-cfg-regs = + /* coded default: KNEE_IP = KNEE_OP = 0, HI_COMP = LO_COMP = 1 */ + <0x01af 0x3248 0x0000 0x0000>, + /* coded default: KNEE_IP = -24, KNEE_OP = -6, HI_COMP = 1/4, LO_COMP = 1 */ + <0x04af 0x324b 0x0010 0x0408>, + /* coded default: KNEE_IP = -42, KNEE_OP = -3, HI_COMP = 0, LO_COMP = 1 */ + <0x04af 0x324b 0x0028 0x0704>, + /* coded default: KNEE_IP = -45, KNEE_OP = -9, HI_COMP = 1/8, LO_COMP = 1 */ + <0x04af 0x324b 0x0018 0x078c>, + /* coded default: KNEE_IP = -30, KNEE_OP = -10.5, HI_COMP = 1/4, LO_COMP = 1 */ + <0x04af 0x324b 0x0010 0x050e>; + gpio-cfg = < + 0x0018 /* GPIO1 => DMIC_CLK */ + 0xffff /* GPIO2 => don't touch */ + 0xffff /* GPIO3 => don't touch */ + 0xffff /* GPIO4 => don't touch */ + >; }; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index a02a77fef360..4121771db104 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2162,6 +2162,110 @@ static const struct of_device_id wm8904_of_match[] = { MODULE_DEVICE_TABLE(of, wm8904_of_match); #endif +static int wm8904_set_pdata_from_of(struct i2c_client *i2c, + struct wm8904_priv *wm8904) +{ + const struct device_node *np = i2c->dev.of_node; + struct wm8904_pdata *pdata; + bool drc_cfgs_is_valid = true; + bool retune_mobile_cfgs_is_valid = true; + int i, j, offset; + u32 val32; + + pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_cfg, + ARRAY_SIZE(pdata->gpio_cfg))) { + dev_dbg(&i2c->dev, "No 'gpio-cfg' property found\n"); + } + + if (of_property_read_u32_array(np, "mic-cfg", pdata->mic_cfg, + ARRAY_SIZE(pdata->mic_cfg))) { + dev_dbg(&i2c->dev, "No 'mic-cfg' property found\n"); + } + + if (of_property_read_s32(np, "num-drc-cfgs", &pdata->num_drc_cfgs)) { + dev_dbg(&i2c->dev, "No 'num-drc-cfgs' property found\n"); + } else if (pdata->num_drc_cfgs < 0) { + dev_err(&i2c->dev, "Negative 'num-drc-cfgs' property found\n"); + pdata->num_drc_cfgs = 0; + } else if (pdata->num_drc_cfgs > 0) { + pdata->drc_cfgs = devm_kzalloc(&i2c->dev, + pdata->num_drc_cfgs * sizeof(struct wm8904_drc_cfg), + GFP_KERNEL); + for (i = 0; i < pdata->num_drc_cfgs && drc_cfgs_is_valid; i++) { + offset = i * WM8904_DRC_REGS; + for (j = 0; j < WM8904_DRC_REGS && drc_cfgs_is_valid; j++) { + if (of_property_read_u32_index(np, + "drc-cfg-regs", + offset + j, + &val32)) { + dev_err(&i2c->dev, + "Invalid 'drc-cfg-regs[%i,%i]' property found\n", i, j); + drc_cfgs_is_valid = false; + } else { + pdata->drc_cfgs[i].regs[j] = val32; + } + } + if (of_property_read_string_index(np, "drc-cfg-names", i, + &pdata->drc_cfgs[i].name)) { + dev_err(&i2c->dev, + "Invalid 'drc-cfg-names[%i]' property found\n", i); + drc_cfgs_is_valid = false; + } + } + } + if (!drc_cfgs_is_valid) { + pdata->num_drc_cfgs = 0; + } + + if (of_property_read_s32(np, "num-retune-mobile-cfgs", &pdata->num_retune_mobile_cfgs)) { + dev_dbg(&i2c->dev, "No 'num-retune-mobile-cfgs' property found\n"); + } else if (pdata->num_retune_mobile_cfgs < 0) { + dev_err(&i2c->dev, "Negative 'num-retune-mobile-cfgs' property found\n"); + pdata->num_retune_mobile_cfgs = 0; + } else if (pdata->num_retune_mobile_cfgs > 0) { + pdata->retune_mobile_cfgs = devm_kzalloc(&i2c->dev, + pdata->num_retune_mobile_cfgs * sizeof(struct wm8904_retune_mobile_cfg), + GFP_KERNEL); + for (i = 0; i < pdata->num_retune_mobile_cfgs && retune_mobile_cfgs_is_valid; i++) { + offset = i * WM8904_EQ_REGS; + for (j = 0; j < WM8904_EQ_REGS && retune_mobile_cfgs_is_valid; j++) { + if (of_property_read_u32_index(np, "retune-mobile-cfg-regs", + offset + j, &val32)) { + dev_err(&i2c->dev, + "Invalid 'retune-mobile-cfg-regs[%i,%i]' property found\n", + i, j); + retune_mobile_cfgs_is_valid = false; + } else { + pdata->retune_mobile_cfgs[i].regs[j] = val32; + } + } + if (of_property_read_u32_index(np, "retune-mobile-cfg-rates", i, + &pdata->retune_mobile_cfgs[i].rate)) { + dev_err(&i2c->dev, + "Invalid 'retune-mobile-cfg-rates[%i]' property found\n", i); + retune_mobile_cfgs_is_valid = false; + } + if (of_property_read_string_index(np, "retune-mobile-cfg-names", + i, &pdata->retune_mobile_cfgs[i].name)) { + dev_err(&i2c->dev, + "Invalid 'retune-mobile-cfg-names[%i]' property found\n", i); + retune_mobile_cfgs_is_valid = false; + } + } + } + if (!retune_mobile_cfgs_is_valid) { + pdata->num_retune_mobile_cfgs = 0; + } + + wm8904->pdata = pdata; + + return 0; +} + static int wm8904_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2196,12 +2300,17 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, if (match == NULL) return -EINVAL; wm8904->devtype = (enum wm8904_type)match->data; + ret = wm8904_set_pdata_from_of(i2c, wm8904); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to set platform data from of: %d\n", ret); + return ret; + } } else { wm8904->devtype = id->driver_data; + wm8904->pdata = i2c->dev.platform_data; } i2c_set_clientdata(i2c, wm8904); - wm8904->pdata = i2c->dev.platform_data; for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++) wm8904->supplies[i].supply = wm8904_supply_names[i]; @@ -2272,7 +2381,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, /* Apply configuration from the platform data. */ if (wm8904->pdata) { for (i = 0; i < WM8904_GPIO_REGS; i++) { - if (!wm8904->pdata->gpio_cfg[i]) + if (wm8904->pdata->gpio_cfg[i] == 0xffff) continue; regmap_update_bits(wm8904->regmap, -- 2.25.1