Unverified Commit 3f58985e authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: codecs: adau1373: drop platform data

Merge series from Nuno Sa <nuno.sa@analog.com>:

Support the powerdown GPIO on ADAU1373.
parents 0d4f74fe ba79bca4
Loading
Loading
Loading
Loading
+111 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/adi,adau1373.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Analog Devices ADAU1373 CODEC

maintainers:
  - Nuno Sá <nuno.sa@analog.com>

description: |
  Analog Devices ADAU1373 Low power codec with speaker and headphone amplifiers.
  https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1373.pdf

allOf:
  - $ref: dai-common.yaml#

properties:
  compatible:
    enum:
      - adi,adau1373

  reg:
    maxItems: 1

  "#sound-dai-cells":
    const: 0

  powerdown-gpios:
    description: GPIO used for hardware power-down.
    maxItems: 1

  adi,micbias1-microvolt:
    description:
      This property sets the microphone bias voltage for the first microphone.
    enum: [1800000, 2200000, 2600000, 2900000]
    default: 2900000

  adi,micbias2-microvolt:
    description:
      This property sets the microphone bias voltage for the second microphone.
    enum: [1800000, 2200000, 2600000, 2900000]
    default: 2900000

  adi,input1-differential:
    description: This property sets the first analog input as differential.
    type: boolean

  adi,input2-differential:
    description: This property sets the second analog input as differential.
    type: boolean

  adi,input3-differential:
    description: This property sets the third analog input as differential.
    type: boolean

  adi,input4-differential:
    description: This property sets the fourth analog input as differential.
    type: boolean

  adi,lineout-differential:
    description: This property sets the line output as differential.
    type: boolean

  adi,lineout-gnd-sense:
    description: This property enables the line output ground sense control.
    type: boolean

  adi,drc-settings:
    description:
      This setting is used to control the dynamic range of the signal. The
      device provides a maximum of three full band DRCs with 13 entries each.
    $ref: /schemas/types.yaml#/definitions/uint8-array
    oneOf:
      - minItems: 13
        maxItems: 13
      - minItems: 26
        maxItems: 26
      - minItems: 39
        maxItems: 39

required:
  - "#sound-dai-cells"
  - compatible
  - reg

unevaluatedProperties: false

examples:
  - |
    #include <dt-bindings/gpio/gpio.h>

    i2c {
        #address-cells = <1>;
        #size-cells = <0>;
        audio-codec@1a {
            compatible = "adi,adau1373";
            reg = <0x1a>;
            #sound-dai-cells = <0>;
            powerdown-gpios = <&gpio 100 GPIO_ACTIVE_LOW>;
            adi,input2-differential;
            adi,input1-differential;
            adi,lineout-differential;
            adi,micbias2-microvolt = <1800000>;
            adi,drc-settings = /bits/ 8 <
                0xff 0xff 0x1 0x2 0xa 0xa 0xd 0x1 0xff 0xff 0x5 0xd 0xff
            >;
        };
    };
...
+1 −0
Original line number Diff line number Diff line
@@ -1521,6 +1521,7 @@ L: linux-sound@vger.kernel.org
S:	Supported
W:	http://wiki.analog.com/
W:	https://ez.analog.com/linux-software-drivers
F:	Documentation/devicetree/bindings/sound/adi,*
F:	sound/soc/codecs/ad1*
F:	sound/soc/codecs/ad7*
F:	sound/soc/codecs/adau*

include/sound/adau1373.h

deleted100644 → 0
+0 −33
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Analog Devices ADAU1373 Audio Codec drive
 *
 * Copyright 2011 Analog Devices Inc.
 * Author: Lars-Peter Clausen <lars@metafoo.de>
 */

#ifndef __SOUND_ADAU1373_H__
#define __SOUND_ADAU1373_H__

enum adau1373_micbias_voltage {
	ADAU1373_MICBIAS_2_9V = 0,
	ADAU1373_MICBIAS_2_2V = 1,
	ADAU1373_MICBIAS_2_6V = 2,
	ADAU1373_MICBIAS_1_8V = 3,
};

#define ADAU1373_DRC_SIZE 13

struct adau1373_platform_data {
	bool input_differential[4];
	bool lineout_differential;
	bool lineout_ground_sense;

	unsigned int num_drc;
	uint8_t drc_setting[3][ADAU1373_DRC_SIZE];

	enum adau1373_micbias_voltage micbias1;
	enum adau1373_micbias_voltage micbias2;
};

#endif
+1 −1
Original line number Diff line number Diff line
@@ -465,7 +465,7 @@ config SND_SOC_ADAU1372_SPI
	select REGMAP_SPI

config SND_SOC_ADAU1373
	tristate
	tristate "Analog Devices ADAU1373 CODEC"
	depends on I2C
	select SND_SOC_ADAU_UTILS

+155 −45
Original line number Diff line number Diff line
@@ -8,8 +8,10 @@

#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/property.h>
#include <linux/i2c.h>
#include <linux/slab.h>

@@ -18,7 +20,6 @@
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
#include <sound/adau1373.h>

#include "adau1373.h"
#include "adau-utils.h"
@@ -30,9 +31,28 @@ struct adau1373_dai {
	bool clock_provider;
};

enum adau1373_micbias_voltage {
	ADAU1373_MICBIAS_2_9V,
	ADAU1373_MICBIAS_2_2V,
	ADAU1373_MICBIAS_2_6V,
	ADAU1373_MICBIAS_1_8V,
};

#define ADAU1373_DRC_SIZE 13

struct adau1373 {
	struct regmap *regmap;
	struct adau1373_dai dais[3];

	bool input_differential[4];
	bool lineout_differential;
	bool lineout_ground_sense;

	unsigned int num_drc;
	u8 drc_setting[3][ADAU1373_DRC_SIZE];

	enum adau1373_micbias_voltage micbias1;
	enum adau1373_micbias_voltage micbias2;
};

#define ADAU1373_INPUT_MODE	0x00
@@ -1332,66 +1352,61 @@ static void adau1373_load_drc_settings(struct adau1373 *adau1373,
		regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]);
}

static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
static int adau1373_get_micbias(unsigned int val,
				enum adau1373_micbias_voltage *micbias)
{
	switch (micbias) {
	case ADAU1373_MICBIAS_2_9V:
	case ADAU1373_MICBIAS_2_2V:
	case ADAU1373_MICBIAS_2_6V:
	case ADAU1373_MICBIAS_1_8V:
		return true;
	switch (val) {
	case 2900000:
		*micbias = ADAU1373_MICBIAS_2_9V;
		return 0;
	case 2200000:
		*micbias = ADAU1373_MICBIAS_2_2V;
		return 0;
	case 2600000:
		*micbias = ADAU1373_MICBIAS_2_6V;
		return 0;
	case 1800000:
		*micbias = ADAU1373_MICBIAS_1_8V;
		return 0;
	default:
		break;
		return -EINVAL;
	}
	return false;
}

static int adau1373_probe(struct snd_soc_component *component)
{
	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
	struct adau1373_platform_data *pdata = component->dev->platform_data;
	bool lineout_differential = false;
	unsigned int val;
	int i;

	if (pdata) {
		if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
			return -EINVAL;

		if (!adau1373_valid_micbias(pdata->micbias1) ||
			!adau1373_valid_micbias(pdata->micbias2))
			return -EINVAL;

		for (i = 0; i < pdata->num_drc; ++i) {
	for (i = 0; i < adau1373->num_drc; ++i) {
		adau1373_load_drc_settings(adau1373, i,
				pdata->drc_setting[i]);
					   adau1373->drc_setting[i]);
	}

	snd_soc_add_component_controls(component, adau1373_drc_controls,
			pdata->num_drc);
				       adau1373->num_drc);

	val = 0;
		for (i = 0; i < 4; ++i) {
			if (pdata->input_differential[i])
	for (i = 0; i < ARRAY_SIZE(adau1373->input_differential); ++i) {
		if (adau1373->input_differential[i])
			val |= BIT(i);
	}
	regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);

	val = 0;
		if (pdata->lineout_differential)
	if (adau1373->lineout_differential)
		val |= ADAU1373_OUTPUT_CTRL_LDIFF;
		if (pdata->lineout_ground_sense)
	if (adau1373->lineout_ground_sense)
		val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
		regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);

		lineout_differential = pdata->lineout_differential;
	regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);

	regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
			(pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
			(pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
	}
		     (adau1373->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
		     (adau1373->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));

	if (!lineout_differential) {
	if (!adau1373->lineout_differential) {
		snd_soc_add_component_controls(component, adau1373_lineout2_controls,
			ARRAY_SIZE(adau1373_lineout2_controls));
	}
@@ -1471,9 +1486,74 @@ static const struct snd_soc_component_driver adau1373_component_driver = {
	.endianness		= 1,
};

static void adau1373_reset(void *reset_gpio)
{
	gpiod_set_value_cansleep(reset_gpio, 1);
}

static int adau1373_parse_fw(struct device *dev, struct adau1373 *adau1373)
{
	int ret, drc_count;
	unsigned int val;

	if (device_property_present(dev, "adi,input1-differential"))
		adau1373->input_differential[0] = true;
	if (device_property_present(dev, "adi,input2-differential"))
		adau1373->input_differential[1] = true;
	if (device_property_present(dev, "adi,input3-differential"))
		adau1373->input_differential[2] = true;
	if (device_property_present(dev, "adi,input4-differential"))
		adau1373->input_differential[3] = true;

	if (device_property_present(dev, "adi,lineout-differential"))
		adau1373->lineout_differential = true;
	if (device_property_present(dev, "adi,lineout-gnd-sense"))
		adau1373->lineout_ground_sense = true;

	ret = device_property_read_u32(dev, "adi,micbias1-microvolt", &val);
	if (!ret) {
		ret = adau1373_get_micbias(val, &adau1373->micbias1);
		if (ret)
			return dev_err_probe(dev, ret,
					     "Failed to get micbias1(%u)\n", val);
	}

	ret = device_property_read_u32(dev, "adi,micbias2-microvolt", &val);
	if (!ret) {
		ret = adau1373_get_micbias(val, &adau1373->micbias2);
		if (ret)
			return dev_err_probe(dev, ret,
					     "Failed to get micbias2(%u)\n", val);
	}

	drc_count = device_property_count_u8(dev, "adi,drc-settings");
	if (drc_count < 0)
		return 0;
	if (drc_count % ADAU1373_DRC_SIZE != 0)
		return dev_err_probe(dev, -EINVAL,
				     "DRC count(%u) not multiple of %u\n",
				     drc_count, ADAU1373_DRC_SIZE);

	adau1373->num_drc = drc_count / ADAU1373_DRC_SIZE;
	if (adau1373->num_drc > ARRAY_SIZE(adau1373->drc_setting))
		return dev_err_probe(dev, -EINVAL,
				     "Too many DRC settings(%u)\n",
				     adau1373->num_drc);

	ret = device_property_read_u8_array(dev, "adi,drc-settings",
					    (u8 *)&adau1373->drc_setting[0],
					    drc_count);
	if (ret)
		return dev_err_probe(dev, ret,
				     "Failed to read DRC settings\n");

	return 0;
}

static int adau1373_i2c_probe(struct i2c_client *client)
{
	struct adau1373 *adau1373;
	struct gpio_desc *gpiod;
	int ret;

	adau1373 = devm_kzalloc(&client->dev, sizeof(*adau1373), GFP_KERNEL);
@@ -1485,10 +1565,33 @@ static int adau1373_i2c_probe(struct i2c_client *client)
	if (IS_ERR(adau1373->regmap))
		return PTR_ERR(adau1373->regmap);

	/*
	 * If the powerdown GPIO is specified, we use it for reset. Otherwise
	 * a software reset is done.
	 */
	gpiod = devm_gpiod_get_optional(&client->dev, "powerdown",
					GPIOD_OUT_HIGH);
	if (IS_ERR(gpiod))
		return PTR_ERR(gpiod);

	if (gpiod) {
		gpiod_set_value_cansleep(gpiod, 0);
		fsleep(10);

		ret = devm_add_action_or_reset(&client->dev, adau1373_reset,
					       gpiod);
		if (ret)
			return ret;
	} else {
		regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
	}

	dev_set_drvdata(&client->dev, adau1373);

	ret = adau1373_parse_fw(&client->dev, adau1373);
	if (ret)
		return ret;

	ret = devm_snd_soc_register_component(&client->dev,
			&adau1373_component_driver,
			adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver));
@@ -1501,9 +1604,16 @@ static const struct i2c_device_id adau1373_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id);

static const struct of_device_id adau1373_of_match[] = {
	{ .compatible = "adi,adau1373", },
	{ }
};
MODULE_DEVICE_TABLE(of, adau1373_of_match);

static struct i2c_driver adau1373_i2c_driver = {
	.driver = {
		.name = "adau1373",
		.of_match_table = adau1373_of_match,
	},
	.probe = adau1373_i2c_probe,
	.id_table = adau1373_i2c_id,