Devicetree
 help / color / mirror / Atom feed
* Re: Applied "ASoC: Add support for Maxim Integrated MAX98927 Amplifier" to the asoc tree
From: Ryan Lee @ 2017-04-25 16:51 UTC (permalink / raw)
  To: Mark Brown
  Cc: mark.rutland, alsa-devel, Kuninori Morimoto, Liam Girdwood, tiwai,
	Srinivas Kandagatla, romain.perier, bardliao, lars, Axel Lin,
	Paul.Handrigan, devicetree, Arnd Bergmann, nh6z, robh+dt, ckeepax,
	Dylan Reid, oder_chiou, Ryan Lee, KCHSU0, linux-kernel
In-Reply-To: <E1cwCZ1-0001o4-Q5@debutante>

'

On Thu, Apr 6, 2017 at 11:55 AM, Mark Brown <broonie@kernel.org> wrote:
> The patch
>
>    ASoC: Add support for Maxim Integrated MAX98927 Amplifier
>
> has been applied to the asoc tree at
>
>    git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
>
> All being well this means that it will be integrated into the linux-next
> tree (usually sometime in the next 24 hours) and sent to Linus during
> the next merge window (or sooner if it is a bug fix), however if
> problems are discovered then the patch may be dropped or reverted.
>
> You may get further e-mails resulting from automated or manual testing
> and review of the tree, please engage with people reporting problems and
> send followup patches addressing any issues that are reported if needed.
>
> If any updates are required or you are submitting further changes they
> should be sent as incremental updates against current git, existing
> patches will not be replaced.
>
> Please add any relevant lists and maintainers to the CCs when replying
> to this mail.
>
> Thanks,
> Mark

I have tried to check MAX98927 driver on linux-next tree and
'git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git' but
have failed.
So I wanted to check the current status of MAX98927 driver.
I'm sorry for top-posting.

>
> From 7c0c2000716e64151b3c0c62026c18f31537ebe9 Mon Sep 17 00:00:00 2001
> From: Ryan Lee <ryans.lee@maximintegrated.com>
> Date: Tue, 4 Apr 2017 02:23:08 +0900
> Subject: [PATCH] ASoC: Add support for Maxim Integrated MAX98927 Amplifier
>
> Signed-off-by: Ryan Lee <ryans.lee@maximintegrated.com>
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
>  .../devicetree/bindings/sound/max98925.txt         |  22 -
>  .../devicetree/bindings/sound/max98926.txt         |  32 -
>  .../devicetree/bindings/sound/max9892x.txt         |  41 +
>  sound/soc/codecs/Kconfig                           |   5 +
>  sound/soc/codecs/Makefile                          |   2 +
>  sound/soc/codecs/max98927.c                        | 841 +++++++++++++++++++++
>  sound/soc/codecs/max98927.h                        | 272 +++++++
>  7 files changed, 1161 insertions(+), 54 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/sound/max98925.txt
>  delete mode 100644 Documentation/devicetree/bindings/sound/max98926.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/max9892x.txt
>  create mode 100644 sound/soc/codecs/max98927.c
>  create mode 100644 sound/soc/codecs/max98927.h
>
> diff --git a/Documentation/devicetree/bindings/sound/max98925.txt b/Documentation/devicetree/bindings/sound/max98925.txt
> deleted file mode 100644
> index 27be63e2aa0d..000000000000
> --- a/Documentation/devicetree/bindings/sound/max98925.txt
> +++ /dev/null
> @@ -1,22 +0,0 @@
> -max98925 audio CODEC
> -
> -This device supports I2C.
> -
> -Required properties:
> -
> -  - compatible : "maxim,max98925"
> -
> -  - vmon-slot-no : slot number used to send voltage information
> -
> -  - imon-slot-no : slot number used to send current information
> -
> -  - reg : the I2C address of the device for I2C
> -
> -Example:
> -
> -codec: max98925@1a {
> -       compatible = "maxim,max98925";
> -       vmon-slot-no = <0>;
> -       imon-slot-no = <2>;
> -       reg = <0x1a>;
> -};
> diff --git a/Documentation/devicetree/bindings/sound/max98926.txt b/Documentation/devicetree/bindings/sound/max98926.txt
> deleted file mode 100644
> index 0b7f4e4d5f9a..000000000000
> --- a/Documentation/devicetree/bindings/sound/max98926.txt
> +++ /dev/null
> @@ -1,32 +0,0 @@
> -max98926 audio CODEC
> -
> -This device supports I2C.
> -
> -Required properties:
> -
> -  - compatible : "maxim,max98926"
> -
> -  - vmon-slot-no : slot number used to send voltage information
> -                   or in inteleave mode this will be used as
> -                   interleave slot.
> -
> -  - imon-slot-no : slot number used to send current information
> -
> -  - interleave-mode : When using two MAX98926 in a system it is
> -                      possible to create ADC data that that will
> -                      overflow the frame size. Digital Audio Interleave
> -                      mode provides a means to output VMON and IMON data
> -                      from two devices on a single DOUT line when running
> -                      smaller frames sizes such as 32 BCLKS per LRCLK or
> -                      48 BCLKS per LRCLK.
> -
> -  - reg : the I2C address of the device for I2C
> -
> -Example:
> -
> -codec: max98926@1a {
> -   compatible = "maxim,max98926";
> -   vmon-slot-no = <0>;
> -   imon-slot-no = <2>;
> -   reg = <0x1a>;
> -};
> diff --git a/Documentation/devicetree/bindings/sound/max9892x.txt b/Documentation/devicetree/bindings/sound/max9892x.txt
> new file mode 100644
> index 000000000000..f6171591ddc6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/max9892x.txt
> @@ -0,0 +1,41 @@
> +Maxim Integrated MAX98925/MAX98926/MAX98927 Speaker Amplifier
> +
> +This device supports I2C.
> +
> +Required properties:
> +
> +  - compatible : should be one of the following
> +    - "maxim,max98925"
> +    - "maxim,max98926"
> +    - "maxim,max98927"
> +
> +  - vmon-slot-no : slot number used to send voltage information
> +                   or in inteleave mode this will be used as
> +                   interleave slot.
> +                   MAX98925/MAX98926 slot range : 0 ~ 30,  Default : 0
> +                   MAX98927 slot range : 0 ~ 15,  Default : 0
> +
> +  - imon-slot-no : slot number used to send current information
> +                   MAX98925/MAX98926 slot range : 0 ~ 30,  Default : 0
> +                   MAX98927 slot range : 0 ~ 15,  Default : 0
> +
> +  - interleave-mode : When using two MAX9892X in a system it is
> +                   possible to create ADC data that that will
> +                   overflow the frame size. Digital Audio Interleave
> +                   mode provides a means to output VMON and IMON data
> +                   from two devices on a single DOUT line when running
> +                   smaller frames sizes such as 32 BCLKS per LRCLK or
> +                   48 BCLKS per LRCLK.
> +                   Range : 0 (off), 1 (on),  Default : 0
> +
> +  - reg : the I2C address of the device for I2C
> +
> +Example:
> +
> +codec: max98927@3a {
> +   compatible = "maxim,max98927";
> +   vmon-slot-no = <0>;
> +   imon-slot-no = <1>;
> +   interleave-mode = <0>;
> +   reg = <0x3a>;
> +};
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index 9e1718a8cb1c..65e31ab88280 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS
>         select SND_SOC_MAX9867 if I2C
>         select SND_SOC_MAX98925 if I2C
>         select SND_SOC_MAX98926 if I2C
> +       select SND_SOC_MAX98927 if I2C
>         select SND_SOC_MAX9850 if I2C
>         select SND_SOC_MAX9860 if I2C
>         select SND_SOC_MAX9768 if I2C
> @@ -585,6 +586,10 @@ config SND_SOC_MAX98925
>  config SND_SOC_MAX98926
>         tristate
>
> +config SND_SOC_MAX98927
> +       tristate "Maxim Integrated MAX98927 Speaker Amplifier"
> +       depends on I2C
> +
>  config SND_SOC_MAX9850
>         tristate
>
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 7e1dad79610b..64656c43200c 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -84,6 +84,7 @@ snd-soc-max98371-objs := max98371.o
>  snd-soc-max9867-objs := max9867.o
>  snd-soc-max98925-objs := max98925.o
>  snd-soc-max98926-objs := max98926.o
> +snd-soc-max98927-objs := max98927.o
>  snd-soc-max9850-objs := max9850.o
>  snd-soc-max9860-objs := max9860.o
>  snd-soc-mc13783-objs := mc13783.o
> @@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_MAX98357A)     += snd-soc-max98357a.o
>  obj-$(CONFIG_SND_SOC_MAX9867)  += snd-soc-max9867.o
>  obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
>  obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
> +obj-$(CONFIG_SND_SOC_MAX98927) += snd-soc-max98927.o
>  obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
>  obj-$(CONFIG_SND_SOC_MAX9860)  += snd-soc-max9860.o
>  obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
> diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
> new file mode 100644
> index 000000000000..b5ee29499e16
> --- /dev/null
> +++ b/sound/soc/codecs/max98927.c
> @@ -0,0 +1,841 @@
> +/*
> + * max98927.c  --  MAX98927 ALSA Soc Audio driver
> + *
> + * Copyright (C) 2016 Maxim Integrated Products
> + * Author: Ryan Lee <ryans.lee@maximintegrated.com>
> + *
> + *  This program is free software; you can redistribute  it and/or modify it
> + *  under  the terms of  the GNU General  Public License as published by the
> + *  Free Software Foundation;  either version 2 of the  License, or (at your
> + *  option) any later version.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/cdev.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +#include <sound/tlv.h>
> +#include "max98927.h"
> +
> +static struct reg_default max98927_reg[] = {
> +       {MAX98927_R0001_INT_RAW1,  0x00},
> +       {MAX98927_R0002_INT_RAW2,  0x00},
> +       {MAX98927_R0003_INT_RAW3,  0x00},
> +       {MAX98927_R0004_INT_STATE1,  0x00},
> +       {MAX98927_R0005_INT_STATE2,  0x00},
> +       {MAX98927_R0006_INT_STATE3,  0x00},
> +       {MAX98927_R0007_INT_FLAG1,  0x00},
> +       {MAX98927_R0008_INT_FLAG2,  0x00},
> +       {MAX98927_R0009_INT_FLAG3,  0x00},
> +       {MAX98927_R000A_INT_EN1,  0x00},
> +       {MAX98927_R000B_INT_EN2,  0x00},
> +       {MAX98927_R000C_INT_EN3,  0x00},
> +       {MAX98927_R000D_INT_FLAG_CLR1,  0x00},
> +       {MAX98927_R000E_INT_FLAG_CLR2,  0x00},
> +       {MAX98927_R000F_INT_FLAG_CLR3,  0x00},
> +       {MAX98927_R0010_IRQ_CTRL,  0x00},
> +       {MAX98927_R0011_CLK_MON,  0x00},
> +       {MAX98927_R0012_WDOG_CTRL,  0x00},
> +       {MAX98927_R0013_WDOG_RST,  0x00},
> +       {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH,  0x00},
> +       {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH,  0x00},
> +       {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS,  0x00},
> +       {MAX98927_R0017_PIN_CFG,  0x55},
> +       {MAX98927_R0018_PCM_RX_EN_A,  0x00},
> +       {MAX98927_R0019_PCM_RX_EN_B,  0x00},
> +       {MAX98927_R001A_PCM_TX_EN_A,  0x00},
> +       {MAX98927_R001B_PCM_TX_EN_B,  0x00},
> +       {MAX98927_R001C_PCM_TX_HIZ_CTRL_A,  0x00},
> +       {MAX98927_R001D_PCM_TX_HIZ_CTRL_B,  0x00},
> +       {MAX98927_R001E_PCM_TX_CH_SRC_A,  0x00},
> +       {MAX98927_R001F_PCM_TX_CH_SRC_B,  0x00},
> +       {MAX98927_R0020_PCM_MODE_CFG,  0x40},
> +       {MAX98927_R0021_PCM_MASTER_MODE,  0x00},
> +       {MAX98927_R0022_PCM_CLK_SETUP,  0x22},
> +       {MAX98927_R0023_PCM_SR_SETUP1,  0x00},
> +       {MAX98927_R0024_PCM_SR_SETUP2,  0x00},
> +       {MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,  0x00},
> +       {MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,  0x00},
> +       {MAX98927_R0027_ICC_RX_EN_A,  0x00},
> +       {MAX98927_R0028_ICC_RX_EN_B,  0x00},
> +       {MAX98927_R002B_ICC_TX_EN_A,  0x00},
> +       {MAX98927_R002C_ICC_TX_EN_B,  0x00},
> +       {MAX98927_R002E_ICC_HIZ_MANUAL_MODE,  0x00},
> +       {MAX98927_R002F_ICC_TX_HIZ_EN_A,  0x00},
> +       {MAX98927_R0030_ICC_TX_HIZ_EN_B,  0x00},
> +       {MAX98927_R0031_ICC_LNK_EN,  0x00},
> +       {MAX98927_R0032_PDM_TX_EN,  0x00},
> +       {MAX98927_R0033_PDM_TX_HIZ_CTRL,  0x00},
> +       {MAX98927_R0034_PDM_TX_CTRL,  0x00},
> +       {MAX98927_R0035_PDM_RX_CTRL,  0x00},
> +       {MAX98927_R0036_AMP_VOL_CTRL,  0x00},
> +       {MAX98927_R0037_AMP_DSP_CFG,  0x02},
> +       {MAX98927_R0038_TONE_GEN_DC_CFG,  0x00},
> +       {MAX98927_R0039_DRE_CTRL,  0x01},
> +       {MAX98927_R003A_AMP_EN,  0x00},
> +       {MAX98927_R003B_SPK_SRC_SEL,  0x00},
> +       {MAX98927_R003C_SPK_GAIN,  0x00},
> +       {MAX98927_R003D_SSM_CFG,  0x01},
> +       {MAX98927_R003E_MEAS_EN,  0x00},
> +       {MAX98927_R003F_MEAS_DSP_CFG,  0x04},
> +       {MAX98927_R0040_BOOST_CTRL0,  0x00},
> +       {MAX98927_R0041_BOOST_CTRL3,  0x00},
> +       {MAX98927_R0042_BOOST_CTRL1,  0x00},
> +       {MAX98927_R0043_MEAS_ADC_CFG,  0x00},
> +       {MAX98927_R0044_MEAS_ADC_BASE_MSB,  0x00},
> +       {MAX98927_R0045_MEAS_ADC_BASE_LSB,  0x00},
> +       {MAX98927_R0046_ADC_CH0_DIVIDE,  0x00},
> +       {MAX98927_R0047_ADC_CH1_DIVIDE,  0x00},
> +       {MAX98927_R0048_ADC_CH2_DIVIDE,  0x00},
> +       {MAX98927_R0049_ADC_CH0_FILT_CFG,  0x00},
> +       {MAX98927_R004A_ADC_CH1_FILT_CFG,  0x00},
> +       {MAX98927_R004B_ADC_CH2_FILT_CFG,  0x00},
> +       {MAX98927_R004C_MEAS_ADC_CH0_READ,  0x00},
> +       {MAX98927_R004D_MEAS_ADC_CH1_READ,  0x00},
> +       {MAX98927_R004E_MEAS_ADC_CH2_READ,  0x00},
> +       {MAX98927_R0051_BROWNOUT_STATUS,  0x00},
> +       {MAX98927_R0052_BROWNOUT_EN,  0x00},
> +       {MAX98927_R0053_BROWNOUT_INFINITE_HOLD,  0x00},
> +       {MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR,  0x00},
> +       {MAX98927_R0055_BROWNOUT_LVL_HOLD,  0x00},
> +       {MAX98927_R005A_BROWNOUT_LVL1_THRESH,  0x00},
> +       {MAX98927_R005B_BROWNOUT_LVL2_THRESH,  0x00},
> +       {MAX98927_R005C_BROWNOUT_LVL3_THRESH,  0x00},
> +       {MAX98927_R005D_BROWNOUT_LVL4_THRESH,  0x00},
> +       {MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS,  0x00},
> +       {MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL,  0x00},
> +       {MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL,  0x00},
> +       {MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE,  0x00},
> +       {MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT,  0x00},
> +       {MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1,  0x00},
> +       {MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2,  0x00},
> +       {MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3,  0x00},
> +       {MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT,  0x00},
> +       {MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1,  0x00},
> +       {MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2,  0x00},
> +       {MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3,  0x00},
> +       {MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT,  0x00},
> +       {MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1,  0x00},
> +       {MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2,  0x00},
> +       {MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3,  0x00},
> +       {MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT,  0x00},
> +       {MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,  0x00},
> +       {MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2,  0x00},
> +       {MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3,  0x00},
> +       {MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,  0x00},
> +       {MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY,  0x00},
> +       {MAX98927_R0084_ENV_TRACK_REL_RATE,  0x00},
> +       {MAX98927_R0085_ENV_TRACK_HOLD_RATE,  0x00},
> +       {MAX98927_R0086_ENV_TRACK_CTRL,  0x00},
> +       {MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,  0x00},
> +       {MAX98927_R00FF_GLOBAL_SHDN,  0x00},
> +       {MAX98927_R0100_SOFT_RESET,  0x00},
> +       {MAX98927_R01FF_REV_ID,  0x40},
> +};
> +
> +static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
> +{
> +       struct snd_soc_codec *codec = codec_dai->codec;
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +       unsigned int mode = 0;
> +       unsigned int format = 0;
> +       unsigned int invert = 0;
> +
> +       dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
> +
> +       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +       case SND_SOC_DAIFMT_CBS_CFS:
> +               mode = MAX98927_PCM_MASTER_MODE_SLAVE;
> +               break;
> +       case SND_SOC_DAIFMT_CBM_CFM:
> +               max98927->master = true;
> +               mode = MAX98927_PCM_MASTER_MODE_MASTER;
> +               break;
> +       default:
> +               dev_err(codec->dev, "DAI clock mode unsupported");
> +               return -EINVAL;
> +       }
> +
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0021_PCM_MASTER_MODE,
> +               MAX98927_PCM_MASTER_MODE_MASK,
> +               mode);
> +
> +       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> +       case SND_SOC_DAIFMT_NB_NF:
> +               break;
> +       case SND_SOC_DAIFMT_IB_NF:
> +               invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
> +               break;
> +       default:
> +               dev_err(codec->dev, "DAI invert mode unsupported");
> +               return -EINVAL;
> +       }
> +
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0020_PCM_MODE_CFG,
> +               MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
> +               invert);
> +
> +       /* interface format */
> +       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> +       case SND_SOC_DAIFMT_I2S:
> +               max98927->iface |= SND_SOC_DAIFMT_I2S;
> +               format = MAX98927_PCM_FORMAT_I2S;
> +               break;
> +       case SND_SOC_DAIFMT_LEFT_J:
> +               max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
> +               format = MAX98927_PCM_FORMAT_LJ;
> +               break;
> +       case SND_SOC_DAIFMT_PDM:
> +               max98927->iface |= SND_SOC_DAIFMT_PDM;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       /* pcm channel configuration */
> +       if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0018_PCM_RX_EN_A,
> +                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
> +                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
> +
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0020_PCM_MODE_CFG,
> +                       MAX98927_PCM_MODE_CFG_FORMAT_MASK,
> +                       format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
> +
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003B_SPK_SRC_SEL,
> +                       MAX98927_SPK_SRC_MASK, 0);
> +
> +       } else
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0018_PCM_RX_EN_A,
> +                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
> +
> +       /* pdm channel configuration */
> +       if (max98927->iface & SND_SOC_DAIFMT_PDM) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0035_PDM_RX_CTRL,
> +                       MAX98927_PDM_RX_EN_MASK, 1);
> +
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003B_SPK_SRC_SEL,
> +                       MAX98927_SPK_SRC_MASK, 3);
> +       } else
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0035_PDM_RX_CTRL,
> +                       MAX98927_PDM_RX_EN_MASK, 0);
> +       return 0;
> +}
> +
> +/* codec MCLK rate in master mode */
> +static const int rate_table[] = {
> +       5644800, 6000000, 6144000, 6500000,
> +       9600000, 11289600, 12000000, 12288000,
> +       13000000, 19200000,
> +};
> +
> +static int max98927_set_clock(struct max98927_priv *max98927,
> +       struct snd_pcm_hw_params *params)
> +{
> +       struct snd_soc_codec *codec = max98927->codec;
> +       /* BCLK/LRCLK ratio calculation */
> +       int blr_clk_ratio = params_channels(params) * max98927->ch_size;
> +       int value;
> +
> +       if (max98927->master) {
> +               int i;
> +               /* match rate to closest value */
> +               for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
> +                       if (rate_table[i] >= max98927->sysclk)
> +                               break;
> +               }
> +               if (i == ARRAY_SIZE(rate_table)) {
> +                       dev_err(codec->dev, "failed to find proper clock rate.\n");
> +                       return -EINVAL;
> +               }
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0021_PCM_MASTER_MODE,
> +                       MAX98927_PCM_MASTER_MODE_MCLK_MASK,
> +                       i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
> +       }
> +
> +       switch (blr_clk_ratio) {
> +       case 32:
> +               value = 2;
> +               break;
> +       case 48:
> +               value = 3;
> +               break;
> +       case 64:
> +               value = 4;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0022_PCM_CLK_SETUP,
> +               MAX98927_PCM_CLK_SETUP_BSEL_MASK,
> +               value);
> +       return 0;
> +}
> +
> +static int max98927_dai_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 max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +       unsigned int sampling_rate = 0;
> +       unsigned int chan_sz = 0;
> +
> +       /* pcm mode configuration */
> +       switch (snd_pcm_format_width(params_format(params))) {
> +       case 16:
> +               chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
> +               break;
> +       case 24:
> +               chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
> +               break;
> +       case 32:
> +               chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
> +               break;
> +       default:
> +               dev_err(codec->dev, "format unsupported %d",
> +                       params_format(params));
> +               goto err;
> +       }
> +
> +       max98927->ch_size = snd_pcm_format_width(params_format(params));
> +
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0020_PCM_MODE_CFG,
> +               MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
> +
> +       dev_dbg(codec->dev, "format supported %d",
> +               params_format(params));
> +
> +       /* sampling rate configuration */
> +       switch (params_rate(params)) {
> +       case 8000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_8000;
> +               break;
> +       case 11025:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_11025;
> +               break;
> +       case 12000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_12000;
> +               break;
> +       case 16000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_16000;
> +               break;
> +       case 22050:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_22050;
> +               break;
> +       case 24000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_24000;
> +               break;
> +       case 32000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_32000;
> +               break;
> +       case 44100:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_44100;
> +               break;
> +       case 48000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_48000;
> +               break;
> +       default:
> +               dev_err(codec->dev, "rate %d not supported\n",
> +                       params_rate(params));
> +               goto err;
> +       }
> +       /* set DAI_SR to correct LRCLK frequency */
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0023_PCM_SR_SETUP1,
> +               MAX98927_PCM_SR_SET1_SR_MASK,
> +               sampling_rate);
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0024_PCM_SR_SETUP2,
> +               MAX98927_PCM_SR_SET2_SR_MASK,
> +               sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
> +
> +       /* set sampling rate of IV */
> +       if (max98927->interleave_mode &&
> +           sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0024_PCM_SR_SETUP2,
> +                       MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
> +                       sampling_rate - 3);
> +       else
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0024_PCM_SR_SETUP2,
> +                       MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
> +                       sampling_rate);
> +       return max98927_set_clock(max98927, params);
> +err:
> +       return -EINVAL;
> +}
> +
> +#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000
> +
> +#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
> +       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
> +
> +static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
> +       int clk_id, unsigned int freq, int dir)
> +{
> +       struct snd_soc_codec *codec = dai->codec;
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +
> +       max98927->sysclk = freq;
> +       return 0;
> +}
> +
> +static const struct snd_soc_dai_ops max98927_dai_ops = {
> +       .set_sysclk = max98927_dai_set_sysclk,
> +       .set_fmt = max98927_dai_set_fmt,
> +       .hw_params = max98927_dai_hw_params,
> +};
> +
> +static int max98927_dac_event(struct snd_soc_dapm_widget *w,
> +       struct snd_kcontrol *kcontrol, int event)
> +{
> +       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +
> +       switch (event) {
> +       case SND_SOC_DAPM_POST_PMU:
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003A_AMP_EN,
> +                       MAX98927_AMP_EN_MASK, 1);
> +               /* enable VMON and IMON */
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003E_MEAS_EN,
> +                       MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
> +                       MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R00FF_GLOBAL_SHDN,
> +                       MAX98927_GLOBAL_EN_MASK, 1);
> +               break;
> +       case SND_SOC_DAPM_POST_PMD:
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R00FF_GLOBAL_SHDN,
> +                       MAX98927_GLOBAL_EN_MASK, 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003A_AMP_EN,
> +                       MAX98927_AMP_EN_MASK, 0);
> +               /* disable VMON and IMON */
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003E_MEAS_EN,
> +                       MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0);
> +               break;
> +       default:
> +               return 0;
> +       }
> +       return 0;
> +}
> +
> +static const char * const max98927_switch_text[] = {
> +       "Left", "Right", "LeftRight"};
> +
> +static const struct soc_enum dai_sel_enum =
> +       SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
> +               MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
> +               3, max98927_switch_text);
> +
> +static const struct snd_kcontrol_new max98927_dai_controls =
> +       SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
> +
> +static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
> +       SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
> +       SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
> +               0, 0, max98927_dac_event,
> +               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
> +       SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
> +               &max98927_dai_controls),
> +       SND_SOC_DAPM_OUTPUT("BE_OUT"),
> +};
> +
> +static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0);
> +static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0);
> +
> +static bool max98927_readable_register(struct device *dev, unsigned int reg)
> +{
> +       switch (reg) {
> +       case MAX98927_R0001_INT_RAW1 ... MAX98927_R0028_ICC_RX_EN_B:
> +       case MAX98927_R002B_ICC_TX_EN_A ... MAX98927_R002C_ICC_TX_EN_B:
> +       case MAX98927_R002E_ICC_HIZ_MANUAL_MODE
> +               ... MAX98927_R004E_MEAS_ADC_CH2_READ:
> +       case MAX98927_R0051_BROWNOUT_STATUS
> +               ... MAX98927_R0055_BROWNOUT_LVL_HOLD:
> +       case MAX98927_R005A_BROWNOUT_LVL1_THRESH
> +               ... MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE:
> +       case MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT
> +               ... MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
> +       case MAX98927_R00FF_GLOBAL_SHDN:
> +       case MAX98927_R0100_SOFT_RESET:
> +       case MAX98927_R01FF_REV_ID:
> +               return true;
> +       default:
> +               return false;
> +       }
> +};
> +
> +static bool max98927_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +       switch (reg) {
> +       case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3:
> +               return true;
> +       default:
> +               return false;
> +       }
> +}
> +
> +static const char * const max98927_boost_voltage_text[] = {
> +       "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V",
> +       "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V",
> +       "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V",
> +       "9.5V", "9.625V", "9.75V", "9.875V", "10V"
> +};
> +
> +static SOC_ENUM_SINGLE_DECL(max98927_boost_voltage,
> +               MAX98927_R0040_BOOST_CTRL0, 0,
> +               max98927_boost_voltage_text);
> +
> +static const char * const max98927_current_limit_text[] = {
> +       "1.00A", "1.10A", "1.20A", "1.30A", "1.40A", "1.50A", "1.60A", "1.70A",
> +       "1.80A", "1.90A", "2.00A", "2.10A", "2.20A", "2.30A", "2.40A", "2.50A",
> +       "2.60A", "2.70A", "2.80A", "2.90A", "3.00A", "3.10A", "3.20A", "3.30A",
> +       "3.40A", "3.50A", "3.60A", "3.70A", "3.80A", "3.90A", "4.00A", "4.10A"
> +};
> +
> +static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
> +               MAX98927_R0042_BOOST_CTRL1, 1,
> +               max98927_current_limit_text);
> +
> +static const struct snd_kcontrol_new max98927_snd_controls[] = {
> +       SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
> +               0, 6, 0,
> +               max98927_spk_tlv),
> +       SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
> +               0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
> +               max98927_digital_tlv),
> +       SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
> +               MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
> +       SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
> +               MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
> +       SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
> +               MAX98927_DRE_EN_SHIFT, 1, 0),
> +       SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
> +               MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
> +       SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
> +       SOC_ENUM("Current Limit", max98927_current_limit),
> +};
> +
> +static const struct snd_soc_dapm_route max98927_audio_map[] = {
> +       {"Amp Enable", NULL, "DAI_OUT"},
> +       {"DAI Sel Mux", "Left", "Amp Enable"},
> +       {"DAI Sel Mux", "Right", "Amp Enable"},
> +       {"DAI Sel Mux", "LeftRight", "Amp Enable"},
> +       {"BE_OUT", NULL, "DAI Sel Mux"},
> +};
> +
> +static struct snd_soc_dai_driver max98927_dai[] = {
> +       {
> +               .name = "max98927-aif1",
> +               .playback = {
> +                       .stream_name = "HiFi Playback",
> +                       .channels_min = 1,
> +                       .channels_max = 2,
> +                       .rates = MAX98927_RATES,
> +                       .formats = MAX98927_FORMATS,
> +               },
> +               .capture = {
> +                       .stream_name = "HiFi Capture",
> +                       .channels_min = 1,
> +                       .channels_max = 2,
> +                       .rates = MAX98927_RATES,
> +                       .formats = MAX98927_FORMATS,
> +               },
> +               .ops = &max98927_dai_ops,
> +       }
> +};
> +
> +static int max98927_probe(struct snd_soc_codec *codec)
> +{
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +
> +       max98927->codec = codec;
> +       codec->control_data = max98927->regmap;
> +       codec->cache_bypass = 1;
> +
> +       /* Software Reset */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
> +
> +       /* IV default slot configuration */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
> +               0xFF);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
> +               0xFF);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
> +               0x80);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
> +               0x1);
> +       /* Set inital volume (+13dB) */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0036_AMP_VOL_CTRL,
> +               0x38);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R003C_SPK_GAIN,
> +               0x05);
> +       /* Enable DC blocker */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0037_AMP_DSP_CFG,
> +               0x03);
> +       /* Enable IMON VMON DC blocker */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R003F_MEAS_DSP_CFG,
> +               0xF7);
> +       /* Boost Output Voltage & Current limit */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0040_BOOST_CTRL0,
> +               0x1C);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0042_BOOST_CTRL1,
> +               0x3E);
> +       /* Measurement ADC config */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0043_MEAS_ADC_CFG,
> +               0x04);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0044_MEAS_ADC_BASE_MSB,
> +               0x00);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0045_MEAS_ADC_BASE_LSB,
> +               0x24);
> +       /* Brownout Level */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
> +               0x06);
> +       /* Envelope Tracking configuration */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
> +               0x08);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0086_ENV_TRACK_CTRL,
> +               0x01);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
> +               0x10);
> +
> +       /* voltage, current slot configuration */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R001E_PCM_TX_CH_SRC_A,
> +               (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
> +               max98927->v_l_slot)&0xFF);
> +
> +       if (max98927->v_l_slot < 8) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
> +                       1 << max98927->v_l_slot, 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001A_PCM_TX_EN_A,
> +                       1 << max98927->v_l_slot,
> +                       1 << max98927->v_l_slot);
> +       } else {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
> +                       1 << (max98927->v_l_slot - 8), 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001B_PCM_TX_EN_B,
> +                       1 << (max98927->v_l_slot - 8),
> +                       1 << (max98927->v_l_slot - 8));
> +       }
> +
> +       if (max98927->i_l_slot < 8) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
> +                       1 << max98927->i_l_slot, 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001A_PCM_TX_EN_A,
> +                       1 << max98927->i_l_slot,
> +                       1 << max98927->i_l_slot);
> +       } else {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
> +                       1 << (max98927->i_l_slot - 8), 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001B_PCM_TX_EN_B,
> +                       1 << (max98927->i_l_slot - 8),
> +                       1 << (max98927->i_l_slot - 8));
> +       }
> +
> +       /* Set interleave mode */
> +       if (max98927->interleave_mode)
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001F_PCM_TX_CH_SRC_B,
> +                       MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
> +                       MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
> +       return 0;
> +}
> +
> +static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
> +       .probe = max98927_probe,
> +       .component_driver = {
> +               .controls = max98927_snd_controls,
> +               .num_controls = ARRAY_SIZE(max98927_snd_controls),
> +               .dapm_widgets = max98927_dapm_widgets,
> +               .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets),
> +               .dapm_routes = max98927_audio_map,
> +               .num_dapm_routes = ARRAY_SIZE(max98927_audio_map),
> +       },
> +};
> +
> +static const struct regmap_config max98927_regmap = {
> +       .reg_bits         = 16,
> +       .val_bits         = 8,
> +       .max_register     = MAX98927_R01FF_REV_ID,
> +       .reg_defaults     = max98927_reg,
> +       .num_reg_defaults = ARRAY_SIZE(max98927_reg),
> +       .readable_reg     = max98927_readable_register,
> +       .volatile_reg     = max98927_volatile_reg,
> +       .cache_type       = REGCACHE_RBTREE,
> +};
> +
> +static void max98927_slot_config(struct i2c_client *i2c,
> +       struct max98927_priv *max98927)
> +{
> +       int value;
> +
> +       if (!of_property_read_u32(i2c->dev.of_node,
> +               "vmon-slot-no", &value))
> +               max98927->v_l_slot = value & 0xF;
> +       else
> +               max98927->v_l_slot = 0;
> +       if (!of_property_read_u32(i2c->dev.of_node,
> +               "imon-slot-no", &value))
> +               max98927->i_l_slot = value & 0xF;
> +       else
> +               max98927->i_l_slot = 1;
> +}
> +
> +static int max98927_i2c_probe(struct i2c_client *i2c,
> +       const struct i2c_device_id *id)
> +{
> +
> +       int ret = 0, value;
> +       int reg = 0;
> +       struct max98927_priv *max98927 = NULL;
> +
> +       max98927 = devm_kzalloc(&i2c->dev,
> +               sizeof(*max98927), GFP_KERNEL);
> +
> +       if (!max98927) {
> +               ret = -ENOMEM;
> +               return ret;
> +       }
> +       i2c_set_clientdata(i2c, max98927);
> +
> +       /* update interleave mode info */
> +       if (!of_property_read_u32(i2c->dev.of_node,
> +               "interleave_mode", &value)) {
> +               if (value > 0)
> +                       max98927->interleave_mode = 1;
> +               else
> +                       max98927->interleave_mode = 0;
> +       } else
> +               max98927->interleave_mode = 0;
> +
> +       /* regmap initialization */
> +       max98927->regmap
> +               = devm_regmap_init_i2c(i2c, &max98927_regmap);
> +       if (IS_ERR(max98927->regmap)) {
> +               ret = PTR_ERR(max98927->regmap);
> +               dev_err(&i2c->dev,
> +                       "Failed to allocate regmap: %d\n", ret);
> +               return ret;
> +       }
> +
> +       /* Check Revision ID */
> +       ret = regmap_read(max98927->regmap,
> +               MAX98927_R01FF_REV_ID, &reg);
> +       if (ret < 0) {
> +               dev_err(&i2c->dev,
> +                       "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
> +               return ret;
> +       }
> +       dev_info(&i2c->dev, "MAX98927 revisionID: 0x%02X\n", reg);
> +
> +       /* voltage/current slot configuration */
> +       max98927_slot_config(i2c, max98927);
> +
> +       /* codec registeration */
> +       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
> +               max98927_dai, ARRAY_SIZE(max98927_dai));
> +       if (ret < 0)
> +               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
> +
> +       return ret;
> +}
> +
> +static int max98927_i2c_remove(struct i2c_client *client)
> +{
> +       snd_soc_unregister_codec(&client->dev);
> +       return 0;
> +}
> +
> +static const struct i2c_device_id max98927_i2c_id[] = {
> +       { "max98927", 0},
> +       { },
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, max98927_i2c_id);
> +
> +#if defined(CONFIG_OF)
> +static const struct of_device_id max98927_of_match[] = {
> +       { .compatible = "maxim,max98927", },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, max98927_of_match);
> +#endif
> +
> +#ifdef CONFIG_ACPI
> +static const struct acpi_device_id max98927_acpi_match[] = {
> +       { "MX98927", 0 },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(acpi, max98927_acpi_match);
> +#endif
> +
> +static struct i2c_driver max98927_i2c_driver = {
> +       .driver = {
> +               .name = "max98927",
> +               .of_match_table = of_match_ptr(max98927_of_match),
> +               .acpi_match_table = ACPI_PTR(max98927_acpi_match),
> +               .pm = NULL,
> +       },
> +       .probe  = max98927_i2c_probe,
> +       .remove = max98927_i2c_remove,
> +       .id_table = max98927_i2c_id,
> +};
> +
> +module_i2c_driver(max98927_i2c_driver)
> +
> +MODULE_DESCRIPTION("ALSA SoC MAX98927 driver");
> +MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
> new file mode 100644
> index 000000000000..ece6a608cbe1
> --- /dev/null
> +++ b/sound/soc/codecs/max98927.h
> @@ -0,0 +1,272 @@
> +/*
> + * max98927.h  --  MAX98927 ALSA Soc Audio driver
> + *
> + * Copyright 2013-15 Maxim Integrated Products
> + * Author: Ryan Lee <ryans.lee@maximintegrated.com>
> + *
> + *  This program is free software; you can redistribute  it and/or modify it
> + *  under  the terms of  the GNU General  Public License as published by the
> + *  Free Software Foundation;  either version 2 of the  License, or (at your
> + *  option) any later version.
> + *
> + */
> +#ifndef _MAX98927_H
> +#define _MAX98927_H
> +
> +/* Register Values */
> +#define MAX98927_R0001_INT_RAW1 0x0001
> +#define MAX98927_R0002_INT_RAW2 0x0002
> +#define MAX98927_R0003_INT_RAW3 0x0003
> +#define MAX98927_R0004_INT_STATE1 0x0004
> +#define MAX98927_R0005_INT_STATE2 0x0005
> +#define MAX98927_R0006_INT_STATE3 0x0006
> +#define MAX98927_R0007_INT_FLAG1 0x0007
> +#define MAX98927_R0008_INT_FLAG2 0x0008
> +#define MAX98927_R0009_INT_FLAG3 0x0009
> +#define MAX98927_R000A_INT_EN1 0x000A
> +#define MAX98927_R000B_INT_EN2 0x000B
> +#define MAX98927_R000C_INT_EN3 0x000C
> +#define MAX98927_R000D_INT_FLAG_CLR1   0x000D
> +#define MAX98927_R000E_INT_FLAG_CLR2   0x000E
> +#define MAX98927_R000F_INT_FLAG_CLR3   0x000F
> +#define MAX98927_R0010_IRQ_CTRL 0x0010
> +#define MAX98927_R0011_CLK_MON 0x0011
> +#define MAX98927_R0012_WDOG_CTRL 0x0012
> +#define MAX98927_R0013_WDOG_RST 0x0013
> +#define MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH 0x0014
> +#define MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH 0x0015
> +#define MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS 0x0016
> +#define MAX98927_R0017_PIN_CFG 0x0017
> +#define MAX98927_R0018_PCM_RX_EN_A 0x0018
> +#define MAX98927_R0019_PCM_RX_EN_B 0x0019
> +#define MAX98927_R001A_PCM_TX_EN_A 0x001A
> +#define MAX98927_R001B_PCM_TX_EN_B 0x001B
> +#define MAX98927_R001C_PCM_TX_HIZ_CTRL_A 0x001C
> +#define MAX98927_R001D_PCM_TX_HIZ_CTRL_B 0x001D
> +#define MAX98927_R001E_PCM_TX_CH_SRC_A 0x001E
> +#define MAX98927_R001F_PCM_TX_CH_SRC_B 0x001F
> +#define MAX98927_R0020_PCM_MODE_CFG 0x0020
> +#define MAX98927_R0021_PCM_MASTER_MODE 0x0021
> +#define MAX98927_R0022_PCM_CLK_SETUP 0x0022
> +#define MAX98927_R0023_PCM_SR_SETUP1 0x0023
> +#define MAX98927_R0024_PCM_SR_SETUP2   0x0024
> +#define MAX98927_R0025_PCM_TO_SPK_MONOMIX_A 0x0025
> +#define MAX98927_R0026_PCM_TO_SPK_MONOMIX_B 0x0026
> +#define MAX98927_R0027_ICC_RX_EN_A 0x0027
> +#define MAX98927_R0028_ICC_RX_EN_B 0x0028
> +#define MAX98927_R002B_ICC_TX_EN_A 0x002B
> +#define MAX98927_R002C_ICC_TX_EN_B 0x002C
> +#define MAX98927_R002E_ICC_HIZ_MANUAL_MODE 0x002E
> +#define MAX98927_R002F_ICC_TX_HIZ_EN_A 0x002F
> +#define MAX98927_R0030_ICC_TX_HIZ_EN_B 0x0030
> +#define MAX98927_R0031_ICC_LNK_EN 0x0031
> +#define MAX98927_R0032_PDM_TX_EN 0x0032
> +#define MAX98927_R0033_PDM_TX_HIZ_CTRL 0x0033
> +#define MAX98927_R0034_PDM_TX_CTRL 0x0034
> +#define MAX98927_R0035_PDM_RX_CTRL 0x0035
> +#define MAX98927_R0036_AMP_VOL_CTRL 0x0036
> +#define MAX98927_R0037_AMP_DSP_CFG 0x0037
> +#define MAX98927_R0038_TONE_GEN_DC_CFG 0x0038
> +#define MAX98927_R0039_DRE_CTRL 0x0039
> +#define MAX98927_R003A_AMP_EN 0x003A
> +#define MAX98927_R003B_SPK_SRC_SEL 0x003B
> +#define MAX98927_R003C_SPK_GAIN 0x003C
> +#define MAX98927_R003D_SSM_CFG 0x003D
> +#define MAX98927_R003E_MEAS_EN 0x003E
> +#define MAX98927_R003F_MEAS_DSP_CFG 0x003F
> +#define MAX98927_R0040_BOOST_CTRL0 0x0040
> +#define MAX98927_R0041_BOOST_CTRL3 0x0041
> +#define MAX98927_R0042_BOOST_CTRL1 0x0042
> +#define MAX98927_R0043_MEAS_ADC_CFG 0x0043
> +#define MAX98927_R0044_MEAS_ADC_BASE_MSB 0x0044
> +#define MAX98927_R0045_MEAS_ADC_BASE_LSB 0x0045
> +#define MAX98927_R0046_ADC_CH0_DIVIDE 0x0046
> +#define MAX98927_R0047_ADC_CH1_DIVIDE 0x0047
> +#define MAX98927_R0048_ADC_CH2_DIVIDE 0x0048
> +#define MAX98927_R0049_ADC_CH0_FILT_CFG 0x0049
> +#define MAX98927_R004A_ADC_CH1_FILT_CFG 0x004A
> +#define MAX98927_R004B_ADC_CH2_FILT_CFG 0x004B
> +#define MAX98927_R004C_MEAS_ADC_CH0_READ 0x004C
> +#define MAX98927_R004D_MEAS_ADC_CH1_READ 0x004D
> +#define MAX98927_R004E_MEAS_ADC_CH2_READ 0x004E
> +#define MAX98927_R0051_BROWNOUT_STATUS 0x0051
> +#define MAX98927_R0052_BROWNOUT_EN 0x0052
> +#define MAX98927_R0053_BROWNOUT_INFINITE_HOLD 0x0053
> +#define MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR 0x0054
> +#define MAX98927_R0055_BROWNOUT_LVL_HOLD 0x0055
> +#define MAX98927_R005A_BROWNOUT_LVL1_THRESH 0x005A
> +#define MAX98927_R005B_BROWNOUT_LVL2_THRESH 0x005B
> +#define MAX98927_R005C_BROWNOUT_LVL3_THRESH 0x005C
> +#define MAX98927_R005D_BROWNOUT_LVL4_THRESH 0x005D
> +#define MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS 0x005E
> +#define MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL 0x005F
> +#define MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL 0x0060
> +#define MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE 0x0061
> +#define MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT 0x0072
> +#define MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1 0x0073
> +#define MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2 0x0074
> +#define MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3 0x0075
> +#define MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT 0x0076
> +#define MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1 0x0077
> +#define MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2 0x0078
> +#define MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3 0x0079
> +#define MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT 0x007A
> +#define MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1 0x007B
> +#define MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2 0x007C
> +#define MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3 0x007D
> +#define MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT 0x007E
> +#define MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1 0x007F
> +#define MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2 0x0080
> +#define MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3 0x0081
> +#define MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM 0x0082
> +#define MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY 0x0083
> +#define MAX98927_R0084_ENV_TRACK_REL_RATE 0x0084
> +#define MAX98927_R0085_ENV_TRACK_HOLD_RATE 0x0085
> +#define MAX98927_R0086_ENV_TRACK_CTRL 0x0086
> +#define MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ 0x0087
> +#define MAX98927_R00FF_GLOBAL_SHDN 0x00FF
> +#define MAX98927_R0100_SOFT_RESET 0x0100
> +#define MAX98927_R01FF_REV_ID 0x01FF
> +
> +/* MAX98927_R0018_PCM_RX_EN_A */
> +#define MAX98927_PCM_RX_CH0_EN (0x1 << 0)
> +#define MAX98927_PCM_RX_CH1_EN (0x1 << 1)
> +#define MAX98927_PCM_RX_CH2_EN (0x1 << 2)
> +#define MAX98927_PCM_RX_CH3_EN (0x1 << 3)
> +#define MAX98927_PCM_RX_CH4_EN (0x1 << 4)
> +#define MAX98927_PCM_RX_CH5_EN (0x1 << 5)
> +#define MAX98927_PCM_RX_CH6_EN (0x1 << 6)
> +#define MAX98927_PCM_RX_CH7_EN (0x1 << 7)
> +
> +/* MAX98927_R001A_PCM_TX_EN_A */
> +#define MAX98927_PCM_TX_CH0_EN (0x1 << 0)
> +#define MAX98927_PCM_TX_CH1_EN (0x1 << 1)
> +#define MAX98927_PCM_TX_CH2_EN (0x1 << 2)
> +#define MAX98927_PCM_TX_CH3_EN (0x1 << 3)
> +#define MAX98927_PCM_TX_CH4_EN (0x1 << 4)
> +#define MAX98927_PCM_TX_CH5_EN (0x1 << 5)
> +#define MAX98927_PCM_TX_CH6_EN (0x1 << 6)
> +#define MAX98927_PCM_TX_CH7_EN (0x1 << 7)
> +
> +/* MAX98927_R001E_PCM_TX_CH_SRC_A */
> +#define MAX98927_PCM_TX_CH_SRC_A_V_SHIFT (0)
> +#define MAX98927_PCM_TX_CH_SRC_A_I_SHIFT (4)
> +
> +/* MAX98927_R001F_PCM_TX_CH_SRC_B */
> +#define MAX98927_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 5)
> +
> +/* MAX98927_R0020_PCM_MODE_CFG */
> +#define MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 2)
> +#define MAX98927_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
> +#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3)
> +#define MAX98927_PCM_FORMAT_I2S (0x0 << 0)
> +#define MAX98927_PCM_FORMAT_LJ (0x1 << 0)
> +
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
> +
> +/* MAX98927_R0021_PCM_MASTER_MODE */
> +#define MAX98927_PCM_MASTER_MODE_MASK (0x3 << 0)
> +#define MAX98927_PCM_MASTER_MODE_SLAVE (0x0 << 0)
> +#define MAX98927_PCM_MASTER_MODE_MASTER (0x3 << 0)
> +
> +#define MAX98927_PCM_MASTER_MODE_MCLK_MASK (0xF << 2)
> +#define MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT (2)
> +
> +/* MAX98927_R0022_PCM_CLK_SETUP */
> +#define MAX98927_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
> +
> +/* MAX98927_R0023_PCM_SR_SETUP1 */
> +#define MAX98927_PCM_SR_SET1_SR_MASK (0xF << 0)
> +
> +#define MAX98927_PCM_SR_SET1_SR_8000 (0x0 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_11025 (0x1 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_12000 (0x2 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_16000 (0x3 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_22050 (0x4 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_24000 (0x5 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_32000 (0x6 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_44100 (0x7 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_48000 (0x8 << 0)
> +
> +/* MAX98927_R0024_PCM_SR_SETUP2 */
> +#define MAX98927_PCM_SR_SET2_SR_MASK (0xF << 4)
> +#define MAX98927_PCM_SR_SET2_SR_SHIFT (4)
> +#define MAX98927_PCM_SR_SET2_IVADC_SR_MASK (0xf << 0)
> +
> +/* MAX98927_R0025_PCM_TO_SPK_MONOMIX_A */
> +#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
> +#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
> +
> +/* MAX98927_R0035_PDM_RX_CTRL */
> +#define MAX98927_PDM_RX_EN_MASK (0x1 << 0)
> +
> +/* MAX98927_R0036_AMP_VOL_CTRL */
> +#define MAX98927_AMP_VOL_SEL (0x1 << 7)
> +#define MAX98927_AMP_VOL_SEL_WIDTH (1)
> +#define MAX98927_AMP_VOL_SEL_SHIFT (7)
> +#define MAX98927_AMP_VOL_MASK (0x7f << 0)
> +#define MAX98927_AMP_VOL_WIDTH (7)
> +#define MAX98927_AMP_VOL_SHIFT (0)
> +
> +/* MAX98927_R0037_AMP_DSP_CFG */
> +#define MAX98927_AMP_DSP_CFG_DCBLK_EN (0x1 << 0)
> +#define MAX98927_AMP_DSP_CFG_DITH_EN (0x1 << 1)
> +#define MAX98927_AMP_DSP_CFG_RMP_BYPASS (0x1 << 4)
> +#define MAX98927_AMP_DSP_CFG_DAC_INV (0x1 << 5)
> +#define MAX98927_AMP_DSP_CFG_RMP_SHIFT (4)
> +
> +/* MAX98927_R0039_DRE_CTRL */
> +#define MAX98927_DRE_CTRL_DRE_EN       (0x1 << 0)
> +#define MAX98927_DRE_EN_SHIFT 0x1
> +
> +/* MAX98927_R003A_AMP_EN */
> +#define MAX98927_AMP_EN_MASK (0x1 << 0)
> +
> +/* MAX98927_R003B_SPK_SRC_SEL */
> +#define MAX98927_SPK_SRC_MASK (0x3 << 0)
> +
> +/* MAX98927_R003C_SPK_GAIN */
> +#define MAX98927_SPK_PCM_GAIN_MASK (0x7 << 0)
> +#define MAX98927_SPK_PDM_GAIN_MASK (0x7 << 4)
> +#define MAX98927_SPK_GAIN_WIDTH (3)
> +
> +/* MAX98927_R003E_MEAS_EN */
> +#define MAX98927_MEAS_V_EN (0x1 << 0)
> +#define MAX98927_MEAS_I_EN (0x1 << 1)
> +
> +/* MAX98927_R0040_BOOST_CTRL0 */
> +#define MAX98927_BOOST_CTRL0_VOUT_MASK (0x1f << 0)
> +#define MAX98927_BOOST_CTRL0_PVDD_MASK (0x1 << 7)
> +#define MAX98927_BOOST_CTRL0_PVDD_EN_SHIFT (7)
> +
> +/* MAX98927_R0052_BROWNOUT_EN */
> +#define MAX98927_BROWNOUT_BDE_EN (0x1 << 0)
> +#define MAX98927_BROWNOUT_AMP_EN (0x1 << 1)
> +#define MAX98927_BROWNOUT_DSP_EN (0x1 << 2)
> +#define MAX98927_BROWNOUT_DSP_SHIFT (2)
> +
> +/* MAX98927_R0100_SOFT_RESET */
> +#define MAX98927_SOFT_RESET (0x1 << 0)
> +
> +/* MAX98927_R00FF_GLOBAL_SHDN */
> +#define MAX98927_GLOBAL_EN_MASK (0x1 << 0)
> +
> +struct max98927_priv {
> +       struct regmap *regmap;
> +       struct snd_soc_codec *codec;
> +       struct max98927_pdata *pdata;
> +       unsigned int spk_gain;
> +       unsigned int sysclk;
> +       unsigned int v_l_slot;
> +       unsigned int i_l_slot;
> +       bool interleave_mode;
> +       unsigned int ch_size;
> +       unsigned int rate;
> +       unsigned int iface;
> +       unsigned int master;
> +       unsigned int digital_gain;
> +};
> +#endif
> --
> 2.11.0
>

^ permalink raw reply

* [PATCH] ARM: dts: Add devicetree for the Raspberry Pi 3, for arm32 (v6)
From: Eric Anholt @ 2017-04-25 16:45 UTC (permalink / raw)
  To: Lee Jones, Florian Fainelli, Olof Johansson, Rob Herring,
	Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Stefan Wahren,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Gerd Hoffmann,
	Eric Anholt

Raspbian and Fedora have decided to support the Pi3 in 32-bit mode for
now, so it's useful to be able to test that mode on an upstream
kernel.  It's also been useful for me to use the same board for 32-bit
and 64-bit development.

Signed-off-by: Eric Anholt <eric-WhKQ6XTQaPysTnJN9+BGXg@public.gmane.org>
---
 arch/arm/boot/dts/Makefile            | 1 +
 arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 arch/arm/boot/dts/bcm2837-rpi-3-b.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 011808490fed..eded842d9978 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -72,6 +72,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
 	bcm2835-rpi-b-plus.dtb \
 	bcm2835-rpi-a-plus.dtb \
 	bcm2836-rpi-2-b.dtb \
+	bcm2837-rpi-3-b.dtb \
 	bcm2835-rpi-zero.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += \
 	bcm4708-asus-rt-ac56u.dtb \
diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
new file mode 100644
index 000000000000..c72a27d908b6
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
@@ -0,0 +1 @@
+#include "arm64/broadcom/bcm2837-rpi-3-b.dts"
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH] ARM: dts: Add devicetree for the Raspberry Pi 3, for arm32 (v5)
From: Eric Anholt @ 2017-04-25 16:45 UTC (permalink / raw)
  To: Stefan Wahren, Lee Jones, Florian Fainelli, Olof Johansson,
	Rob Herring, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Gerd Hoffmann,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <68d88bf7-1f47-4056-3b70-7b97d9a02953-eS4NqCHxEME@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 1625 bytes --]

Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org> writes:

> Am 24.04.2017 um 22:00 schrieb Eric Anholt:
>> Raspbian and Fedora have decided to support the Pi3 in 32-bit mode for
>> now, so it's useful to be able to test that mode on an upstream
>> kernel.  It's also been useful for me to use the same board for 32-bit
>> and 64-bit development.
>>
>> Signed-off-by: Eric Anholt <eric-WhKQ6XTQaPysTnJN9+BGXg@public.gmane.org>
>> ---
>>  arch/arm/boot/dts/Makefile            | 1 +
>>  arch/arm/boot/dts/bcm2837-rpi-3.b.dts | 1 +
>>  2 files changed, 2 insertions(+)
>>  create mode 100644 arch/arm/boot/dts/bcm2837-rpi-3.b.dts
>>
>> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
>> index 011808490fed..eded842d9978 100644
>> --- a/arch/arm/boot/dts/Makefile
>> +++ b/arch/arm/boot/dts/Makefile
>> @@ -72,6 +72,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
>>  	bcm2835-rpi-b-plus.dtb \
>>  	bcm2835-rpi-a-plus.dtb \
>>  	bcm2836-rpi-2-b.dtb \
>> +	bcm2837-rpi-3-b.dtb \
>>  	bcm2835-rpi-zero.dtb
>>  dtb-$(CONFIG_ARCH_BCM_5301X) += \
>>  	bcm4708-asus-rt-ac56u.dtb \
>> diff --git a/arch/arm/boot/dts/bcm2837-rpi-3.b.dts b/arch/arm/boot/dts/bcm2837-rpi-3.b.dts
>> new file mode 100644
>> index 000000000000..8c8aa4d1e9b3
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/bcm2837-rpi-3.b.dts
>> @@ -0,0 +1 @@
>> +#include "arm64/broadcom/bcm2837-rpi-3.b.dts"
>
> Looks like a typo in the dts filename and in the include ( dot instead
> of dash ).

Sorry about that, everyone.  I remember doing builds of the patch, but
maybe things succeeded because there was already a .dtb present in my
tree or something.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply

* Re: [PATCH v2 2/2] of: Add unit tests for applying overlays
From: Rob Herring @ 2017-04-25 16:44 UTC (permalink / raw)
  To: Frank Rowand
  Cc: Stephen Boyd, Michal Marek, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, Linux Kbuild mailing list
In-Reply-To: <1493075119-32026-3-git-send-email-frowand.list@gmail.com>

On Mon, Apr 24, 2017 at 6:05 PM,  <frowand.list@gmail.com> wrote:
> From: Frank Rowand <frank.rowand@sony.com>
>
> Existing overlay unit tests examine individual pieces of the overlay
> code.  The new tests target the entire process of applying an overlay.

Just a few nits.

> Signed-off-by: Frank Rowand <frank.rowand@sony.com>

[...]

> diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
> index 18bbb4517e25..cc76b3b81eab 100644
> --- a/drivers/of/of_private.h
> +++ b/drivers/of/of_private.h
> @@ -55,6 +55,17 @@ static inline int of_property_notify(int action, struct device_node *np,
>  }
>  #endif /* CONFIG_OF_DYNAMIC */
>
> +#ifdef CONFIG_OF_UNITTEST
> +extern void __init unittest_unflatten_overlay_base(void);
> +extern void *__unflatten_device_tree(const void *blob,

This can and should be outside the ifdef.

> +                             struct device_node *dad,
> +                             struct device_node **mynodes,
> +                             void *(*dt_alloc)(u64 size, u64 align),
> +                             bool detached);
> +#else
> +static inline void unittest_unflatten_overlay_base(void) {};
> +#endif
> +
>  /**
>   * General utilities for working with live trees.
>   *

[...]

> diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
> index 62db55b97c10..884f6c1f8ae9 100644
> --- a/drivers/of/unittest.c
> +++ b/drivers/of/unittest.c
> @@ -8,6 +8,7 @@
>  #include <linux/err.h>
>  #include <linux/errno.h>
>  #include <linux/hashtable.h>
> +#include <linux/libfdt.h>
>  #include <linux/of.h>
>  #include <linux/of_fdt.h>
>  #include <linux/of_irq.h>
> @@ -1925,6 +1926,320 @@ static void __init of_unittest_overlay(void)
>  static inline void __init of_unittest_overlay(void) { }
>  #endif
>
> +#ifdef CONFIG_OF_OVERLAY

This can move down to...

> +
> +/*
> + * __dtb_ot_begin[] and __dtb_ot_end[] are created by cmd_dt_S_dtb
> + * in scripts/Makefile.lib
> + */
> +
> +#define OVERLAY_INFO_EXTERN(name) \
> +       extern uint8_t __dtb_##name##_begin[]; \
> +       extern uint8_t __dtb_##name##_end[]
> +
> +#define OVERLAY_INFO(name, expected) \
> +{      .dtb_begin       = __dtb_##name##_begin, \
> +       .dtb_end         = __dtb_##name##_end, \
> +       .expected_result = expected, \
> +}
> +
> +struct overlay_info {
> +       uint8_t            *dtb_begin;
> +       uint8_t            *dtb_end;
> +       void               *data;
> +       struct device_node *np_overlay;
> +       int                expected_result;
> +       int                overlay_id;
> +};
> +
> +OVERLAY_INFO_EXTERN(overlay_base);
> +OVERLAY_INFO_EXTERN(overlay);
> +OVERLAY_INFO_EXTERN(overlay_bad_phandle);

...here. Maybe we want to move all this to a separate file instead.

> +
> +/* order of entries is hard-coded into users of overlays[] */
> +struct overlay_info overlays[] = {

static?

> +       OVERLAY_INFO(overlay_base, -9999),
> +       OVERLAY_INFO(overlay, 0),
> +       OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
> +       {}
> +};

[...]

> @@ -1962,6 +2277,9 @@ static int __init of_unittest(void)
>         /* Double check linkage after removing testcase data */
>         of_unittest_check_tree_linkage();
>
> +

Extra blank line.

> +       of_unittest_overlay_high_level();
> +
>         pr_info("end of unittest - %i passed, %i failed\n",
>                 unittest_results.passed, unittest_results.failed);
>
> --
> Frank Rowand <frank.rowand@sony.com>
>

^ permalink raw reply

* Re: [PATCH v8 1/3] backlight arcxcnn add arc to vendor prefix
From: Jingoo Han @ 2017-04-25 16:36 UTC (permalink / raw)
  To: 'Olimpiu Dejeu', 'Rob Herring'
  Cc: 'Lee Jones', linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, 'Brian Dodge',
	'Joe Perches', 'Matthew D'Asaro',
	'Daniel Thompson'
In-Reply-To: <2aac01d2bd24$17449a90$45cdcfb0$@arcticsand.com>

On Monday, April 24, 2017 1:56 PM, Olimpiu Dejeu wrote:
> 
> On Mon, April 24, 2017 11:10 AM, Rob Herring < robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> 
> > On Wed, Mar 15, 2017 at 2:45 PM, Olimpiu Dejeu <olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org>
> wrote:
> >> backlight: Add arc to vendor prefixes
> >> Signed-off-by: Olimpiu Dejeu <olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org>
> >> ---
> >> v8:
> >> - Version to match other patches in set
> >>
> >>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> >>  1 file changed, 1 insertion(+)
> >>
> >> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt
> >> b/Documentation/devicetree/bindings/vendor-prefixes.txt
> >> index 16d3b5e..6f33a4b 100644
> >> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> >> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> >> @@ -28,6 +28,7 @@ andestech     Andes Technology Corporation
> >>  apm    Applied Micro Circuits Corporation (APM)
> >>  aptina Aptina Imaging
> >>  arasan Arasan Chip Systems
> >> +arc    Arctic Sand
> 
> >arc is also a cpu arch. While not a vendor, it could be confusing. How
> about "arctic" >instead?
> 
> Rob, will do, i.e. I will change it to "arctic"

Hi Olimpiu,

Oh, "arc" and "arctic" is totally different.
In my opinion, one of the purposes of DT is to describe hardware stuffs.
So, please use more detailed words.

> 
> >BTW, some reason your patches are not going to the DT list.
> 
> 
> I'm emailing to devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, I think this is the correct
> list. Please advise.

DT is some kind of ABI. It means that changing DT names such as property names
is not easy, after DT patches were merged. So, if someone want to add new DT stuff
into the vanilla kernel, that patch should be reviewed more thoroughly
than normal patches about driver stuffs.

Thanks,
Jingoo Han

> 
> 
> >Rob
> Olimpiu
> 


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes
From: Philipp Zabel @ 2017-04-25 16:32 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Jonathan Cameron, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Greg Kroah-Hartman, Wolfram Sang, Rob Herring, Mark Rutland,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Colin Ian King,
	Paul Gortmaker, kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <e53bbf82-793f-b22f-2e9b-4bd377446351-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

On Tue, 2017-04-25 at 16:55 +0200, Peter Rosin wrote:
> On 2017-04-25 16:16, Peter Rosin wrote:
> > On 2017-04-24 16:59, Philipp Zabel wrote:
> >> On Mon, 2017-04-24 at 16:36 +0200, Peter Rosin wrote:
> >> [...]
> >>>> How about an atomic use_count on the mux_control, a bool shared that is
> >>>> only set by the first consumer, and controls whether selecting locks?
> >>>
> >>> That has the drawback that it is hard to restore the mux-control in a safe
> >>> way so that exclusive consumers are allowed after the last shared consumer
> >>> puts the mux away.
> >>
> >> True.
> >>
> >>> Agreed, it's a corner case, but I had this very similar
> >>> patch going through the compiler when I got this mail. Does it work as well
> >>> as what you suggested?
> >>
> >> Yes, this patch works just as well.
> > 
> > Right, as expected :-) However, I don't like it much. It divides the mux
> > consumers into two camps in a way that makes it difficult to select which
> > camp a consumer should be in.
> > 
> > E.g. consider the iio-mux. The current implementation only supports quick
> > accesses that fit the mux_control_get_shared case. But if that mux in the
> > future needs to grow continuous buffered accesses, I think there will be
> > pressure to switch it over to the exclusive mode. Because that is a lot
> > closer to what you are doing with the video-mux. And then what? It will be
> > impossible to predict if the end user is going to use buffered accesses or
> > not...
> > 
> > So, I think the best approach is to skip the distinction between shared
> > and exclusive consumers and instead implement the locking with an ordinary
> > semaphore (instead of the old rwsem or the current mutex). Semaphores don't
> > have the property that the same task should down/up them (mutexes require
> > that for lock/unlock, and is also the reason for the lockdep complaint) and
> > thus fits better for long-time use such as yours or the above iio-mux with
> > buffered accesses. It should also hopefully be cheaper that an rwsem, and
> > not have any downgrade_write calls thus possibly keeping Greg sufficiently
> > happy...

No idea whether this will placate Greg, but it does work for the
video-mux case.
The documentation for mux_control_(try_)select should mention that these
calls will hold the mux lock until deselect is called, and the
documentation for mux_control_select should probably mention that it
will block until the lock is released.

> > Sure, consumers can still dig themselves into a hole by not calling deselect
> > as they should, but at least I think it can be made to work w/o dividing the
> > consumers...
> 
> Like this (only compile-tested). Philipp, it should work the same as with
> the rwsem in v13 and earlier. At least for your case...

regards
Philipp

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: Applied "ASoC: Add support for Maxim Integrated MAX98927 Amplifier" to the asoc tree
From: Mark Brown @ 2017-04-25 16:28 UTC (permalink / raw)
  To: Ryan Lee
  Cc: Liam Girdwood, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	Kuninori Morimoto, Arnd Bergmann,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lars-Qo5EllUWu/uELgA04lAiVw, bardliao-Rasf1IRRPZFBDgjK7y7TUQ,
	nh6z-fFIq/eER6g8, KCHSU0-KrzQf0k3Iz9BDgjK7y7TUQ, Axel Lin,
	romain.perier-ZGY8ohtN/8qB+jHODAdFcQ, Srinivas Kandagatla,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dylan Reid
In-Reply-To: <CAN4-oj=suA8Bx_QLGOvGkjr=CgUwhPibNRk31Y_JaBydZX6USg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 544 bytes --]

On Tue, Apr 25, 2017 at 09:24:34AM -0700, Ryan Lee wrote:
> I was not able to see any activities about MAX98927 driver after previous mail.
> Is there anything wrong with this driver?

Please don't top post, reply in line with needed context.  This allows
readers to readily follow the flow of conversation and understand what
you are talking about and also helps ensure that everything in the
discussion is being addressed.

I'm not sure what communication you're expecting...  if nobody is
complaining about your driver that's probably good?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH v2 15/18] dt-bindings: sound: Add bindings for Cirrus Logic Madera codecs
From: Richard Fitzgerald @ 2017-04-25 16:27 UTC (permalink / raw)
  To: Mark Brown
  Cc: gnurou, alsa-devel, jason, devicetree, linus.walleij, patches,
	linux-kernel, linux-gpio, robh+dt, tglx, lee.jones
In-Reply-To: <20170425155257.s6m4wgrzxxsxcggo@sirena.org.uk>

On Tue, 2017-04-25 at 16:52 +0100, Mark Brown wrote:
> On Mon, Apr 24, 2017 at 05:08:41PM +0100, Richard Fitzgerald wrote:
> > The Cirrus Logic Madera codecs are a family of related codecs with
> > extensive digital and analogue I/O, digital mixing and routing,
> > signal processing and programmable DSPs.
> 
> Please submit patches using subject lines reflecting the style for the
> subsystem.  This makes it easier for people to identify relevant
> patches.  Look at what existing commits in the area you're changing are
> doing and make sure your subject lines visually resemble what they're
> doing.
> 
> > +Required properties:
> > +  - compatible : One of the following chip-specific strings:
> > +        "cirrus,cs47l35-codec"
> > +        "cirrus,cs47l85-codec"
> > +        "cirrus,cs47l90-codec"
> 
> You shouldn't have compatible strings for subfunctions of a MFD unless
> these represent meaningful reusable IPs that can exist separately from
> the parent chip, that's clearly not the case here.  All you're doing
> here is encoding Linux internal abstractions which aren't OS neutral and
> might change in future (for example clocking might move more into the
> clock API).

While that's nice, the of_node doesn't get populated if there isn't a
compatible string. And people don't like workarounds for the missing
of_node.

^ permalink raw reply

* Re: Applied "ASoC: Add support for Maxim Integrated MAX98927 Amplifier" to the asoc tree
From: Ryan Lee @ 2017-04-25 16:24 UTC (permalink / raw)
  To: Mark Brown
  Cc: Liam Girdwood, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	Kuninori Morimoto, Arnd Bergmann,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lars-Qo5EllUWu/uELgA04lAiVw, bardliao-Rasf1IRRPZFBDgjK7y7TUQ,
	nh6z-fFIq/eER6g8, KCHSU0-KrzQf0k3Iz9BDgjK7y7TUQ, Axel Lin,
	romain.perier-ZGY8ohtN/8qB+jHODAdFcQ, Srinivas Kandagatla,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dylan Reid
In-Reply-To: <E1cwCZ1-0001o4-Q5@debutante>

I was not able to see any activities about MAX98927 driver after previous mail.
Is there anything wrong with this driver?


On Thu, Apr 6, 2017 at 11:55 AM, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> The patch
>
>    ASoC: Add support for Maxim Integrated MAX98927 Amplifier
>
> has been applied to the asoc tree at
>
>    git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
>
> All being well this means that it will be integrated into the linux-next
> tree (usually sometime in the next 24 hours) and sent to Linus during
> the next merge window (or sooner if it is a bug fix), however if
> problems are discovered then the patch may be dropped or reverted.
>
> You may get further e-mails resulting from automated or manual testing
> and review of the tree, please engage with people reporting problems and
> send followup patches addressing any issues that are reported if needed.
>
> If any updates are required or you are submitting further changes they
> should be sent as incremental updates against current git, existing
> patches will not be replaced.
>
> Please add any relevant lists and maintainers to the CCs when replying
> to this mail.
>
> Thanks,
> Mark
>
> From 7c0c2000716e64151b3c0c62026c18f31537ebe9 Mon Sep 17 00:00:00 2001
> From: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
> Date: Tue, 4 Apr 2017 02:23:08 +0900
> Subject: [PATCH] ASoC: Add support for Maxim Integrated MAX98927 Amplifier
>
> Signed-off-by: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
> Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---
>  .../devicetree/bindings/sound/max98925.txt         |  22 -
>  .../devicetree/bindings/sound/max98926.txt         |  32 -
>  .../devicetree/bindings/sound/max9892x.txt         |  41 +
>  sound/soc/codecs/Kconfig                           |   5 +
>  sound/soc/codecs/Makefile                          |   2 +
>  sound/soc/codecs/max98927.c                        | 841 +++++++++++++++++++++
>  sound/soc/codecs/max98927.h                        | 272 +++++++
>  7 files changed, 1161 insertions(+), 54 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/sound/max98925.txt
>  delete mode 100644 Documentation/devicetree/bindings/sound/max98926.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/max9892x.txt
>  create mode 100644 sound/soc/codecs/max98927.c
>  create mode 100644 sound/soc/codecs/max98927.h
>
> diff --git a/Documentation/devicetree/bindings/sound/max98925.txt b/Documentation/devicetree/bindings/sound/max98925.txt
> deleted file mode 100644
> index 27be63e2aa0d..000000000000
> --- a/Documentation/devicetree/bindings/sound/max98925.txt
> +++ /dev/null
> @@ -1,22 +0,0 @@
> -max98925 audio CODEC
> -
> -This device supports I2C.
> -
> -Required properties:
> -
> -  - compatible : "maxim,max98925"
> -
> -  - vmon-slot-no : slot number used to send voltage information
> -
> -  - imon-slot-no : slot number used to send current information
> -
> -  - reg : the I2C address of the device for I2C
> -
> -Example:
> -
> -codec: max98925@1a {
> -       compatible = "maxim,max98925";
> -       vmon-slot-no = <0>;
> -       imon-slot-no = <2>;
> -       reg = <0x1a>;
> -};
> diff --git a/Documentation/devicetree/bindings/sound/max98926.txt b/Documentation/devicetree/bindings/sound/max98926.txt
> deleted file mode 100644
> index 0b7f4e4d5f9a..000000000000
> --- a/Documentation/devicetree/bindings/sound/max98926.txt
> +++ /dev/null
> @@ -1,32 +0,0 @@
> -max98926 audio CODEC
> -
> -This device supports I2C.
> -
> -Required properties:
> -
> -  - compatible : "maxim,max98926"
> -
> -  - vmon-slot-no : slot number used to send voltage information
> -                   or in inteleave mode this will be used as
> -                   interleave slot.
> -
> -  - imon-slot-no : slot number used to send current information
> -
> -  - interleave-mode : When using two MAX98926 in a system it is
> -                      possible to create ADC data that that will
> -                      overflow the frame size. Digital Audio Interleave
> -                      mode provides a means to output VMON and IMON data
> -                      from two devices on a single DOUT line when running
> -                      smaller frames sizes such as 32 BCLKS per LRCLK or
> -                      48 BCLKS per LRCLK.
> -
> -  - reg : the I2C address of the device for I2C
> -
> -Example:
> -
> -codec: max98926@1a {
> -   compatible = "maxim,max98926";
> -   vmon-slot-no = <0>;
> -   imon-slot-no = <2>;
> -   reg = <0x1a>;
> -};
> diff --git a/Documentation/devicetree/bindings/sound/max9892x.txt b/Documentation/devicetree/bindings/sound/max9892x.txt
> new file mode 100644
> index 000000000000..f6171591ddc6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/max9892x.txt
> @@ -0,0 +1,41 @@
> +Maxim Integrated MAX98925/MAX98926/MAX98927 Speaker Amplifier
> +
> +This device supports I2C.
> +
> +Required properties:
> +
> +  - compatible : should be one of the following
> +    - "maxim,max98925"
> +    - "maxim,max98926"
> +    - "maxim,max98927"
> +
> +  - vmon-slot-no : slot number used to send voltage information
> +                   or in inteleave mode this will be used as
> +                   interleave slot.
> +                   MAX98925/MAX98926 slot range : 0 ~ 30,  Default : 0
> +                   MAX98927 slot range : 0 ~ 15,  Default : 0
> +
> +  - imon-slot-no : slot number used to send current information
> +                   MAX98925/MAX98926 slot range : 0 ~ 30,  Default : 0
> +                   MAX98927 slot range : 0 ~ 15,  Default : 0
> +
> +  - interleave-mode : When using two MAX9892X in a system it is
> +                   possible to create ADC data that that will
> +                   overflow the frame size. Digital Audio Interleave
> +                   mode provides a means to output VMON and IMON data
> +                   from two devices on a single DOUT line when running
> +                   smaller frames sizes such as 32 BCLKS per LRCLK or
> +                   48 BCLKS per LRCLK.
> +                   Range : 0 (off), 1 (on),  Default : 0
> +
> +  - reg : the I2C address of the device for I2C
> +
> +Example:
> +
> +codec: max98927@3a {
> +   compatible = "maxim,max98927";
> +   vmon-slot-no = <0>;
> +   imon-slot-no = <1>;
> +   interleave-mode = <0>;
> +   reg = <0x3a>;
> +};
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index 9e1718a8cb1c..65e31ab88280 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS
>         select SND_SOC_MAX9867 if I2C
>         select SND_SOC_MAX98925 if I2C
>         select SND_SOC_MAX98926 if I2C
> +       select SND_SOC_MAX98927 if I2C
>         select SND_SOC_MAX9850 if I2C
>         select SND_SOC_MAX9860 if I2C
>         select SND_SOC_MAX9768 if I2C
> @@ -585,6 +586,10 @@ config SND_SOC_MAX98925
>  config SND_SOC_MAX98926
>         tristate
>
> +config SND_SOC_MAX98927
> +       tristate "Maxim Integrated MAX98927 Speaker Amplifier"
> +       depends on I2C
> +
>  config SND_SOC_MAX9850
>         tristate
>
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 7e1dad79610b..64656c43200c 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -84,6 +84,7 @@ snd-soc-max98371-objs := max98371.o
>  snd-soc-max9867-objs := max9867.o
>  snd-soc-max98925-objs := max98925.o
>  snd-soc-max98926-objs := max98926.o
> +snd-soc-max98927-objs := max98927.o
>  snd-soc-max9850-objs := max9850.o
>  snd-soc-max9860-objs := max9860.o
>  snd-soc-mc13783-objs := mc13783.o
> @@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_MAX98357A)     += snd-soc-max98357a.o
>  obj-$(CONFIG_SND_SOC_MAX9867)  += snd-soc-max9867.o
>  obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
>  obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
> +obj-$(CONFIG_SND_SOC_MAX98927) += snd-soc-max98927.o
>  obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
>  obj-$(CONFIG_SND_SOC_MAX9860)  += snd-soc-max9860.o
>  obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
> diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
> new file mode 100644
> index 000000000000..b5ee29499e16
> --- /dev/null
> +++ b/sound/soc/codecs/max98927.c
> @@ -0,0 +1,841 @@
> +/*
> + * max98927.c  --  MAX98927 ALSA Soc Audio driver
> + *
> + * Copyright (C) 2016 Maxim Integrated Products
> + * Author: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
> + *
> + *  This program is free software; you can redistribute  it and/or modify it
> + *  under  the terms of  the GNU General  Public License as published by the
> + *  Free Software Foundation;  either version 2 of the  License, or (at your
> + *  option) any later version.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/cdev.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +#include <sound/tlv.h>
> +#include "max98927.h"
> +
> +static struct reg_default max98927_reg[] = {
> +       {MAX98927_R0001_INT_RAW1,  0x00},
> +       {MAX98927_R0002_INT_RAW2,  0x00},
> +       {MAX98927_R0003_INT_RAW3,  0x00},
> +       {MAX98927_R0004_INT_STATE1,  0x00},
> +       {MAX98927_R0005_INT_STATE2,  0x00},
> +       {MAX98927_R0006_INT_STATE3,  0x00},
> +       {MAX98927_R0007_INT_FLAG1,  0x00},
> +       {MAX98927_R0008_INT_FLAG2,  0x00},
> +       {MAX98927_R0009_INT_FLAG3,  0x00},
> +       {MAX98927_R000A_INT_EN1,  0x00},
> +       {MAX98927_R000B_INT_EN2,  0x00},
> +       {MAX98927_R000C_INT_EN3,  0x00},
> +       {MAX98927_R000D_INT_FLAG_CLR1,  0x00},
> +       {MAX98927_R000E_INT_FLAG_CLR2,  0x00},
> +       {MAX98927_R000F_INT_FLAG_CLR3,  0x00},
> +       {MAX98927_R0010_IRQ_CTRL,  0x00},
> +       {MAX98927_R0011_CLK_MON,  0x00},
> +       {MAX98927_R0012_WDOG_CTRL,  0x00},
> +       {MAX98927_R0013_WDOG_RST,  0x00},
> +       {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH,  0x00},
> +       {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH,  0x00},
> +       {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS,  0x00},
> +       {MAX98927_R0017_PIN_CFG,  0x55},
> +       {MAX98927_R0018_PCM_RX_EN_A,  0x00},
> +       {MAX98927_R0019_PCM_RX_EN_B,  0x00},
> +       {MAX98927_R001A_PCM_TX_EN_A,  0x00},
> +       {MAX98927_R001B_PCM_TX_EN_B,  0x00},
> +       {MAX98927_R001C_PCM_TX_HIZ_CTRL_A,  0x00},
> +       {MAX98927_R001D_PCM_TX_HIZ_CTRL_B,  0x00},
> +       {MAX98927_R001E_PCM_TX_CH_SRC_A,  0x00},
> +       {MAX98927_R001F_PCM_TX_CH_SRC_B,  0x00},
> +       {MAX98927_R0020_PCM_MODE_CFG,  0x40},
> +       {MAX98927_R0021_PCM_MASTER_MODE,  0x00},
> +       {MAX98927_R0022_PCM_CLK_SETUP,  0x22},
> +       {MAX98927_R0023_PCM_SR_SETUP1,  0x00},
> +       {MAX98927_R0024_PCM_SR_SETUP2,  0x00},
> +       {MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,  0x00},
> +       {MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,  0x00},
> +       {MAX98927_R0027_ICC_RX_EN_A,  0x00},
> +       {MAX98927_R0028_ICC_RX_EN_B,  0x00},
> +       {MAX98927_R002B_ICC_TX_EN_A,  0x00},
> +       {MAX98927_R002C_ICC_TX_EN_B,  0x00},
> +       {MAX98927_R002E_ICC_HIZ_MANUAL_MODE,  0x00},
> +       {MAX98927_R002F_ICC_TX_HIZ_EN_A,  0x00},
> +       {MAX98927_R0030_ICC_TX_HIZ_EN_B,  0x00},
> +       {MAX98927_R0031_ICC_LNK_EN,  0x00},
> +       {MAX98927_R0032_PDM_TX_EN,  0x00},
> +       {MAX98927_R0033_PDM_TX_HIZ_CTRL,  0x00},
> +       {MAX98927_R0034_PDM_TX_CTRL,  0x00},
> +       {MAX98927_R0035_PDM_RX_CTRL,  0x00},
> +       {MAX98927_R0036_AMP_VOL_CTRL,  0x00},
> +       {MAX98927_R0037_AMP_DSP_CFG,  0x02},
> +       {MAX98927_R0038_TONE_GEN_DC_CFG,  0x00},
> +       {MAX98927_R0039_DRE_CTRL,  0x01},
> +       {MAX98927_R003A_AMP_EN,  0x00},
> +       {MAX98927_R003B_SPK_SRC_SEL,  0x00},
> +       {MAX98927_R003C_SPK_GAIN,  0x00},
> +       {MAX98927_R003D_SSM_CFG,  0x01},
> +       {MAX98927_R003E_MEAS_EN,  0x00},
> +       {MAX98927_R003F_MEAS_DSP_CFG,  0x04},
> +       {MAX98927_R0040_BOOST_CTRL0,  0x00},
> +       {MAX98927_R0041_BOOST_CTRL3,  0x00},
> +       {MAX98927_R0042_BOOST_CTRL1,  0x00},
> +       {MAX98927_R0043_MEAS_ADC_CFG,  0x00},
> +       {MAX98927_R0044_MEAS_ADC_BASE_MSB,  0x00},
> +       {MAX98927_R0045_MEAS_ADC_BASE_LSB,  0x00},
> +       {MAX98927_R0046_ADC_CH0_DIVIDE,  0x00},
> +       {MAX98927_R0047_ADC_CH1_DIVIDE,  0x00},
> +       {MAX98927_R0048_ADC_CH2_DIVIDE,  0x00},
> +       {MAX98927_R0049_ADC_CH0_FILT_CFG,  0x00},
> +       {MAX98927_R004A_ADC_CH1_FILT_CFG,  0x00},
> +       {MAX98927_R004B_ADC_CH2_FILT_CFG,  0x00},
> +       {MAX98927_R004C_MEAS_ADC_CH0_READ,  0x00},
> +       {MAX98927_R004D_MEAS_ADC_CH1_READ,  0x00},
> +       {MAX98927_R004E_MEAS_ADC_CH2_READ,  0x00},
> +       {MAX98927_R0051_BROWNOUT_STATUS,  0x00},
> +       {MAX98927_R0052_BROWNOUT_EN,  0x00},
> +       {MAX98927_R0053_BROWNOUT_INFINITE_HOLD,  0x00},
> +       {MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR,  0x00},
> +       {MAX98927_R0055_BROWNOUT_LVL_HOLD,  0x00},
> +       {MAX98927_R005A_BROWNOUT_LVL1_THRESH,  0x00},
> +       {MAX98927_R005B_BROWNOUT_LVL2_THRESH,  0x00},
> +       {MAX98927_R005C_BROWNOUT_LVL3_THRESH,  0x00},
> +       {MAX98927_R005D_BROWNOUT_LVL4_THRESH,  0x00},
> +       {MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS,  0x00},
> +       {MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL,  0x00},
> +       {MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL,  0x00},
> +       {MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE,  0x00},
> +       {MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT,  0x00},
> +       {MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1,  0x00},
> +       {MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2,  0x00},
> +       {MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3,  0x00},
> +       {MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT,  0x00},
> +       {MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1,  0x00},
> +       {MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2,  0x00},
> +       {MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3,  0x00},
> +       {MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT,  0x00},
> +       {MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1,  0x00},
> +       {MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2,  0x00},
> +       {MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3,  0x00},
> +       {MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT,  0x00},
> +       {MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,  0x00},
> +       {MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2,  0x00},
> +       {MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3,  0x00},
> +       {MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,  0x00},
> +       {MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY,  0x00},
> +       {MAX98927_R0084_ENV_TRACK_REL_RATE,  0x00},
> +       {MAX98927_R0085_ENV_TRACK_HOLD_RATE,  0x00},
> +       {MAX98927_R0086_ENV_TRACK_CTRL,  0x00},
> +       {MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,  0x00},
> +       {MAX98927_R00FF_GLOBAL_SHDN,  0x00},
> +       {MAX98927_R0100_SOFT_RESET,  0x00},
> +       {MAX98927_R01FF_REV_ID,  0x40},
> +};
> +
> +static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
> +{
> +       struct snd_soc_codec *codec = codec_dai->codec;
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +       unsigned int mode = 0;
> +       unsigned int format = 0;
> +       unsigned int invert = 0;
> +
> +       dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
> +
> +       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +       case SND_SOC_DAIFMT_CBS_CFS:
> +               mode = MAX98927_PCM_MASTER_MODE_SLAVE;
> +               break;
> +       case SND_SOC_DAIFMT_CBM_CFM:
> +               max98927->master = true;
> +               mode = MAX98927_PCM_MASTER_MODE_MASTER;
> +               break;
> +       default:
> +               dev_err(codec->dev, "DAI clock mode unsupported");
> +               return -EINVAL;
> +       }
> +
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0021_PCM_MASTER_MODE,
> +               MAX98927_PCM_MASTER_MODE_MASK,
> +               mode);
> +
> +       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> +       case SND_SOC_DAIFMT_NB_NF:
> +               break;
> +       case SND_SOC_DAIFMT_IB_NF:
> +               invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
> +               break;
> +       default:
> +               dev_err(codec->dev, "DAI invert mode unsupported");
> +               return -EINVAL;
> +       }
> +
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0020_PCM_MODE_CFG,
> +               MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
> +               invert);
> +
> +       /* interface format */
> +       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> +       case SND_SOC_DAIFMT_I2S:
> +               max98927->iface |= SND_SOC_DAIFMT_I2S;
> +               format = MAX98927_PCM_FORMAT_I2S;
> +               break;
> +       case SND_SOC_DAIFMT_LEFT_J:
> +               max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
> +               format = MAX98927_PCM_FORMAT_LJ;
> +               break;
> +       case SND_SOC_DAIFMT_PDM:
> +               max98927->iface |= SND_SOC_DAIFMT_PDM;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       /* pcm channel configuration */
> +       if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0018_PCM_RX_EN_A,
> +                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
> +                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
> +
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0020_PCM_MODE_CFG,
> +                       MAX98927_PCM_MODE_CFG_FORMAT_MASK,
> +                       format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
> +
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003B_SPK_SRC_SEL,
> +                       MAX98927_SPK_SRC_MASK, 0);
> +
> +       } else
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0018_PCM_RX_EN_A,
> +                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
> +
> +       /* pdm channel configuration */
> +       if (max98927->iface & SND_SOC_DAIFMT_PDM) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0035_PDM_RX_CTRL,
> +                       MAX98927_PDM_RX_EN_MASK, 1);
> +
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003B_SPK_SRC_SEL,
> +                       MAX98927_SPK_SRC_MASK, 3);
> +       } else
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0035_PDM_RX_CTRL,
> +                       MAX98927_PDM_RX_EN_MASK, 0);
> +       return 0;
> +}
> +
> +/* codec MCLK rate in master mode */
> +static const int rate_table[] = {
> +       5644800, 6000000, 6144000, 6500000,
> +       9600000, 11289600, 12000000, 12288000,
> +       13000000, 19200000,
> +};
> +
> +static int max98927_set_clock(struct max98927_priv *max98927,
> +       struct snd_pcm_hw_params *params)
> +{
> +       struct snd_soc_codec *codec = max98927->codec;
> +       /* BCLK/LRCLK ratio calculation */
> +       int blr_clk_ratio = params_channels(params) * max98927->ch_size;
> +       int value;
> +
> +       if (max98927->master) {
> +               int i;
> +               /* match rate to closest value */
> +               for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
> +                       if (rate_table[i] >= max98927->sysclk)
> +                               break;
> +               }
> +               if (i == ARRAY_SIZE(rate_table)) {
> +                       dev_err(codec->dev, "failed to find proper clock rate.\n");
> +                       return -EINVAL;
> +               }
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0021_PCM_MASTER_MODE,
> +                       MAX98927_PCM_MASTER_MODE_MCLK_MASK,
> +                       i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
> +       }
> +
> +       switch (blr_clk_ratio) {
> +       case 32:
> +               value = 2;
> +               break;
> +       case 48:
> +               value = 3;
> +               break;
> +       case 64:
> +               value = 4;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0022_PCM_CLK_SETUP,
> +               MAX98927_PCM_CLK_SETUP_BSEL_MASK,
> +               value);
> +       return 0;
> +}
> +
> +static int max98927_dai_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 max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +       unsigned int sampling_rate = 0;
> +       unsigned int chan_sz = 0;
> +
> +       /* pcm mode configuration */
> +       switch (snd_pcm_format_width(params_format(params))) {
> +       case 16:
> +               chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
> +               break;
> +       case 24:
> +               chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
> +               break;
> +       case 32:
> +               chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
> +               break;
> +       default:
> +               dev_err(codec->dev, "format unsupported %d",
> +                       params_format(params));
> +               goto err;
> +       }
> +
> +       max98927->ch_size = snd_pcm_format_width(params_format(params));
> +
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0020_PCM_MODE_CFG,
> +               MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
> +
> +       dev_dbg(codec->dev, "format supported %d",
> +               params_format(params));
> +
> +       /* sampling rate configuration */
> +       switch (params_rate(params)) {
> +       case 8000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_8000;
> +               break;
> +       case 11025:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_11025;
> +               break;
> +       case 12000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_12000;
> +               break;
> +       case 16000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_16000;
> +               break;
> +       case 22050:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_22050;
> +               break;
> +       case 24000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_24000;
> +               break;
> +       case 32000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_32000;
> +               break;
> +       case 44100:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_44100;
> +               break;
> +       case 48000:
> +               sampling_rate = MAX98927_PCM_SR_SET1_SR_48000;
> +               break;
> +       default:
> +               dev_err(codec->dev, "rate %d not supported\n",
> +                       params_rate(params));
> +               goto err;
> +       }
> +       /* set DAI_SR to correct LRCLK frequency */
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0023_PCM_SR_SETUP1,
> +               MAX98927_PCM_SR_SET1_SR_MASK,
> +               sampling_rate);
> +       regmap_update_bits(max98927->regmap,
> +               MAX98927_R0024_PCM_SR_SETUP2,
> +               MAX98927_PCM_SR_SET2_SR_MASK,
> +               sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
> +
> +       /* set sampling rate of IV */
> +       if (max98927->interleave_mode &&
> +           sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0024_PCM_SR_SETUP2,
> +                       MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
> +                       sampling_rate - 3);
> +       else
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R0024_PCM_SR_SETUP2,
> +                       MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
> +                       sampling_rate);
> +       return max98927_set_clock(max98927, params);
> +err:
> +       return -EINVAL;
> +}
> +
> +#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000
> +
> +#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
> +       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
> +
> +static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
> +       int clk_id, unsigned int freq, int dir)
> +{
> +       struct snd_soc_codec *codec = dai->codec;
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +
> +       max98927->sysclk = freq;
> +       return 0;
> +}
> +
> +static const struct snd_soc_dai_ops max98927_dai_ops = {
> +       .set_sysclk = max98927_dai_set_sysclk,
> +       .set_fmt = max98927_dai_set_fmt,
> +       .hw_params = max98927_dai_hw_params,
> +};
> +
> +static int max98927_dac_event(struct snd_soc_dapm_widget *w,
> +       struct snd_kcontrol *kcontrol, int event)
> +{
> +       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +
> +       switch (event) {
> +       case SND_SOC_DAPM_POST_PMU:
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003A_AMP_EN,
> +                       MAX98927_AMP_EN_MASK, 1);
> +               /* enable VMON and IMON */
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003E_MEAS_EN,
> +                       MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
> +                       MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R00FF_GLOBAL_SHDN,
> +                       MAX98927_GLOBAL_EN_MASK, 1);
> +               break;
> +       case SND_SOC_DAPM_POST_PMD:
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R00FF_GLOBAL_SHDN,
> +                       MAX98927_GLOBAL_EN_MASK, 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003A_AMP_EN,
> +                       MAX98927_AMP_EN_MASK, 0);
> +               /* disable VMON and IMON */
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R003E_MEAS_EN,
> +                       MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0);
> +               break;
> +       default:
> +               return 0;
> +       }
> +       return 0;
> +}
> +
> +static const char * const max98927_switch_text[] = {
> +       "Left", "Right", "LeftRight"};
> +
> +static const struct soc_enum dai_sel_enum =
> +       SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
> +               MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
> +               3, max98927_switch_text);
> +
> +static const struct snd_kcontrol_new max98927_dai_controls =
> +       SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
> +
> +static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
> +       SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
> +       SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
> +               0, 0, max98927_dac_event,
> +               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
> +       SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
> +               &max98927_dai_controls),
> +       SND_SOC_DAPM_OUTPUT("BE_OUT"),
> +};
> +
> +static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0);
> +static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0);
> +
> +static bool max98927_readable_register(struct device *dev, unsigned int reg)
> +{
> +       switch (reg) {
> +       case MAX98927_R0001_INT_RAW1 ... MAX98927_R0028_ICC_RX_EN_B:
> +       case MAX98927_R002B_ICC_TX_EN_A ... MAX98927_R002C_ICC_TX_EN_B:
> +       case MAX98927_R002E_ICC_HIZ_MANUAL_MODE
> +               ... MAX98927_R004E_MEAS_ADC_CH2_READ:
> +       case MAX98927_R0051_BROWNOUT_STATUS
> +               ... MAX98927_R0055_BROWNOUT_LVL_HOLD:
> +       case MAX98927_R005A_BROWNOUT_LVL1_THRESH
> +               ... MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE:
> +       case MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT
> +               ... MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
> +       case MAX98927_R00FF_GLOBAL_SHDN:
> +       case MAX98927_R0100_SOFT_RESET:
> +       case MAX98927_R01FF_REV_ID:
> +               return true;
> +       default:
> +               return false;
> +       }
> +};
> +
> +static bool max98927_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +       switch (reg) {
> +       case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3:
> +               return true;
> +       default:
> +               return false;
> +       }
> +}
> +
> +static const char * const max98927_boost_voltage_text[] = {
> +       "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V",
> +       "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V",
> +       "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V",
> +       "9.5V", "9.625V", "9.75V", "9.875V", "10V"
> +};
> +
> +static SOC_ENUM_SINGLE_DECL(max98927_boost_voltage,
> +               MAX98927_R0040_BOOST_CTRL0, 0,
> +               max98927_boost_voltage_text);
> +
> +static const char * const max98927_current_limit_text[] = {
> +       "1.00A", "1.10A", "1.20A", "1.30A", "1.40A", "1.50A", "1.60A", "1.70A",
> +       "1.80A", "1.90A", "2.00A", "2.10A", "2.20A", "2.30A", "2.40A", "2.50A",
> +       "2.60A", "2.70A", "2.80A", "2.90A", "3.00A", "3.10A", "3.20A", "3.30A",
> +       "3.40A", "3.50A", "3.60A", "3.70A", "3.80A", "3.90A", "4.00A", "4.10A"
> +};
> +
> +static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
> +               MAX98927_R0042_BOOST_CTRL1, 1,
> +               max98927_current_limit_text);
> +
> +static const struct snd_kcontrol_new max98927_snd_controls[] = {
> +       SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
> +               0, 6, 0,
> +               max98927_spk_tlv),
> +       SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
> +               0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
> +               max98927_digital_tlv),
> +       SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
> +               MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
> +       SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
> +               MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
> +       SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
> +               MAX98927_DRE_EN_SHIFT, 1, 0),
> +       SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
> +               MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
> +       SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
> +       SOC_ENUM("Current Limit", max98927_current_limit),
> +};
> +
> +static const struct snd_soc_dapm_route max98927_audio_map[] = {
> +       {"Amp Enable", NULL, "DAI_OUT"},
> +       {"DAI Sel Mux", "Left", "Amp Enable"},
> +       {"DAI Sel Mux", "Right", "Amp Enable"},
> +       {"DAI Sel Mux", "LeftRight", "Amp Enable"},
> +       {"BE_OUT", NULL, "DAI Sel Mux"},
> +};
> +
> +static struct snd_soc_dai_driver max98927_dai[] = {
> +       {
> +               .name = "max98927-aif1",
> +               .playback = {
> +                       .stream_name = "HiFi Playback",
> +                       .channels_min = 1,
> +                       .channels_max = 2,
> +                       .rates = MAX98927_RATES,
> +                       .formats = MAX98927_FORMATS,
> +               },
> +               .capture = {
> +                       .stream_name = "HiFi Capture",
> +                       .channels_min = 1,
> +                       .channels_max = 2,
> +                       .rates = MAX98927_RATES,
> +                       .formats = MAX98927_FORMATS,
> +               },
> +               .ops = &max98927_dai_ops,
> +       }
> +};
> +
> +static int max98927_probe(struct snd_soc_codec *codec)
> +{
> +       struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
> +
> +       max98927->codec = codec;
> +       codec->control_data = max98927->regmap;
> +       codec->cache_bypass = 1;
> +
> +       /* Software Reset */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
> +
> +       /* IV default slot configuration */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
> +               0xFF);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
> +               0xFF);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
> +               0x80);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
> +               0x1);
> +       /* Set inital volume (+13dB) */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0036_AMP_VOL_CTRL,
> +               0x38);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R003C_SPK_GAIN,
> +               0x05);
> +       /* Enable DC blocker */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0037_AMP_DSP_CFG,
> +               0x03);
> +       /* Enable IMON VMON DC blocker */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R003F_MEAS_DSP_CFG,
> +               0xF7);
> +       /* Boost Output Voltage & Current limit */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0040_BOOST_CTRL0,
> +               0x1C);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0042_BOOST_CTRL1,
> +               0x3E);
> +       /* Measurement ADC config */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0043_MEAS_ADC_CFG,
> +               0x04);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0044_MEAS_ADC_BASE_MSB,
> +               0x00);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0045_MEAS_ADC_BASE_LSB,
> +               0x24);
> +       /* Brownout Level */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
> +               0x06);
> +       /* Envelope Tracking configuration */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
> +               0x08);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0086_ENV_TRACK_CTRL,
> +               0x01);
> +       regmap_write(max98927->regmap,
> +               MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
> +               0x10);
> +
> +       /* voltage, current slot configuration */
> +       regmap_write(max98927->regmap,
> +               MAX98927_R001E_PCM_TX_CH_SRC_A,
> +               (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
> +               max98927->v_l_slot)&0xFF);
> +
> +       if (max98927->v_l_slot < 8) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
> +                       1 << max98927->v_l_slot, 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001A_PCM_TX_EN_A,
> +                       1 << max98927->v_l_slot,
> +                       1 << max98927->v_l_slot);
> +       } else {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
> +                       1 << (max98927->v_l_slot - 8), 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001B_PCM_TX_EN_B,
> +                       1 << (max98927->v_l_slot - 8),
> +                       1 << (max98927->v_l_slot - 8));
> +       }
> +
> +       if (max98927->i_l_slot < 8) {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
> +                       1 << max98927->i_l_slot, 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001A_PCM_TX_EN_A,
> +                       1 << max98927->i_l_slot,
> +                       1 << max98927->i_l_slot);
> +       } else {
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
> +                       1 << (max98927->i_l_slot - 8), 0);
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001B_PCM_TX_EN_B,
> +                       1 << (max98927->i_l_slot - 8),
> +                       1 << (max98927->i_l_slot - 8));
> +       }
> +
> +       /* Set interleave mode */
> +       if (max98927->interleave_mode)
> +               regmap_update_bits(max98927->regmap,
> +                       MAX98927_R001F_PCM_TX_CH_SRC_B,
> +                       MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
> +                       MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
> +       return 0;
> +}
> +
> +static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
> +       .probe = max98927_probe,
> +       .component_driver = {
> +               .controls = max98927_snd_controls,
> +               .num_controls = ARRAY_SIZE(max98927_snd_controls),
> +               .dapm_widgets = max98927_dapm_widgets,
> +               .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets),
> +               .dapm_routes = max98927_audio_map,
> +               .num_dapm_routes = ARRAY_SIZE(max98927_audio_map),
> +       },
> +};
> +
> +static const struct regmap_config max98927_regmap = {
> +       .reg_bits         = 16,
> +       .val_bits         = 8,
> +       .max_register     = MAX98927_R01FF_REV_ID,
> +       .reg_defaults     = max98927_reg,
> +       .num_reg_defaults = ARRAY_SIZE(max98927_reg),
> +       .readable_reg     = max98927_readable_register,
> +       .volatile_reg     = max98927_volatile_reg,
> +       .cache_type       = REGCACHE_RBTREE,
> +};
> +
> +static void max98927_slot_config(struct i2c_client *i2c,
> +       struct max98927_priv *max98927)
> +{
> +       int value;
> +
> +       if (!of_property_read_u32(i2c->dev.of_node,
> +               "vmon-slot-no", &value))
> +               max98927->v_l_slot = value & 0xF;
> +       else
> +               max98927->v_l_slot = 0;
> +       if (!of_property_read_u32(i2c->dev.of_node,
> +               "imon-slot-no", &value))
> +               max98927->i_l_slot = value & 0xF;
> +       else
> +               max98927->i_l_slot = 1;
> +}
> +
> +static int max98927_i2c_probe(struct i2c_client *i2c,
> +       const struct i2c_device_id *id)
> +{
> +
> +       int ret = 0, value;
> +       int reg = 0;
> +       struct max98927_priv *max98927 = NULL;
> +
> +       max98927 = devm_kzalloc(&i2c->dev,
> +               sizeof(*max98927), GFP_KERNEL);
> +
> +       if (!max98927) {
> +               ret = -ENOMEM;
> +               return ret;
> +       }
> +       i2c_set_clientdata(i2c, max98927);
> +
> +       /* update interleave mode info */
> +       if (!of_property_read_u32(i2c->dev.of_node,
> +               "interleave_mode", &value)) {
> +               if (value > 0)
> +                       max98927->interleave_mode = 1;
> +               else
> +                       max98927->interleave_mode = 0;
> +       } else
> +               max98927->interleave_mode = 0;
> +
> +       /* regmap initialization */
> +       max98927->regmap
> +               = devm_regmap_init_i2c(i2c, &max98927_regmap);
> +       if (IS_ERR(max98927->regmap)) {
> +               ret = PTR_ERR(max98927->regmap);
> +               dev_err(&i2c->dev,
> +                       "Failed to allocate regmap: %d\n", ret);
> +               return ret;
> +       }
> +
> +       /* Check Revision ID */
> +       ret = regmap_read(max98927->regmap,
> +               MAX98927_R01FF_REV_ID, &reg);
> +       if (ret < 0) {
> +               dev_err(&i2c->dev,
> +                       "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
> +               return ret;
> +       }
> +       dev_info(&i2c->dev, "MAX98927 revisionID: 0x%02X\n", reg);
> +
> +       /* voltage/current slot configuration */
> +       max98927_slot_config(i2c, max98927);
> +
> +       /* codec registeration */
> +       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
> +               max98927_dai, ARRAY_SIZE(max98927_dai));
> +       if (ret < 0)
> +               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
> +
> +       return ret;
> +}
> +
> +static int max98927_i2c_remove(struct i2c_client *client)
> +{
> +       snd_soc_unregister_codec(&client->dev);
> +       return 0;
> +}
> +
> +static const struct i2c_device_id max98927_i2c_id[] = {
> +       { "max98927", 0},
> +       { },
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, max98927_i2c_id);
> +
> +#if defined(CONFIG_OF)
> +static const struct of_device_id max98927_of_match[] = {
> +       { .compatible = "maxim,max98927", },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, max98927_of_match);
> +#endif
> +
> +#ifdef CONFIG_ACPI
> +static const struct acpi_device_id max98927_acpi_match[] = {
> +       { "MX98927", 0 },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(acpi, max98927_acpi_match);
> +#endif
> +
> +static struct i2c_driver max98927_i2c_driver = {
> +       .driver = {
> +               .name = "max98927",
> +               .of_match_table = of_match_ptr(max98927_of_match),
> +               .acpi_match_table = ACPI_PTR(max98927_acpi_match),
> +               .pm = NULL,
> +       },
> +       .probe  = max98927_i2c_probe,
> +       .remove = max98927_i2c_remove,
> +       .id_table = max98927_i2c_id,
> +};
> +
> +module_i2c_driver(max98927_i2c_driver)
> +
> +MODULE_DESCRIPTION("ALSA SoC MAX98927 driver");
> +MODULE_AUTHOR("Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
> new file mode 100644
> index 000000000000..ece6a608cbe1
> --- /dev/null
> +++ b/sound/soc/codecs/max98927.h
> @@ -0,0 +1,272 @@
> +/*
> + * max98927.h  --  MAX98927 ALSA Soc Audio driver
> + *
> + * Copyright 2013-15 Maxim Integrated Products
> + * Author: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
> + *
> + *  This program is free software; you can redistribute  it and/or modify it
> + *  under  the terms of  the GNU General  Public License as published by the
> + *  Free Software Foundation;  either version 2 of the  License, or (at your
> + *  option) any later version.
> + *
> + */
> +#ifndef _MAX98927_H
> +#define _MAX98927_H
> +
> +/* Register Values */
> +#define MAX98927_R0001_INT_RAW1 0x0001
> +#define MAX98927_R0002_INT_RAW2 0x0002
> +#define MAX98927_R0003_INT_RAW3 0x0003
> +#define MAX98927_R0004_INT_STATE1 0x0004
> +#define MAX98927_R0005_INT_STATE2 0x0005
> +#define MAX98927_R0006_INT_STATE3 0x0006
> +#define MAX98927_R0007_INT_FLAG1 0x0007
> +#define MAX98927_R0008_INT_FLAG2 0x0008
> +#define MAX98927_R0009_INT_FLAG3 0x0009
> +#define MAX98927_R000A_INT_EN1 0x000A
> +#define MAX98927_R000B_INT_EN2 0x000B
> +#define MAX98927_R000C_INT_EN3 0x000C
> +#define MAX98927_R000D_INT_FLAG_CLR1   0x000D
> +#define MAX98927_R000E_INT_FLAG_CLR2   0x000E
> +#define MAX98927_R000F_INT_FLAG_CLR3   0x000F
> +#define MAX98927_R0010_IRQ_CTRL 0x0010
> +#define MAX98927_R0011_CLK_MON 0x0011
> +#define MAX98927_R0012_WDOG_CTRL 0x0012
> +#define MAX98927_R0013_WDOG_RST 0x0013
> +#define MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH 0x0014
> +#define MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH 0x0015
> +#define MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS 0x0016
> +#define MAX98927_R0017_PIN_CFG 0x0017
> +#define MAX98927_R0018_PCM_RX_EN_A 0x0018
> +#define MAX98927_R0019_PCM_RX_EN_B 0x0019
> +#define MAX98927_R001A_PCM_TX_EN_A 0x001A
> +#define MAX98927_R001B_PCM_TX_EN_B 0x001B
> +#define MAX98927_R001C_PCM_TX_HIZ_CTRL_A 0x001C
> +#define MAX98927_R001D_PCM_TX_HIZ_CTRL_B 0x001D
> +#define MAX98927_R001E_PCM_TX_CH_SRC_A 0x001E
> +#define MAX98927_R001F_PCM_TX_CH_SRC_B 0x001F
> +#define MAX98927_R0020_PCM_MODE_CFG 0x0020
> +#define MAX98927_R0021_PCM_MASTER_MODE 0x0021
> +#define MAX98927_R0022_PCM_CLK_SETUP 0x0022
> +#define MAX98927_R0023_PCM_SR_SETUP1 0x0023
> +#define MAX98927_R0024_PCM_SR_SETUP2   0x0024
> +#define MAX98927_R0025_PCM_TO_SPK_MONOMIX_A 0x0025
> +#define MAX98927_R0026_PCM_TO_SPK_MONOMIX_B 0x0026
> +#define MAX98927_R0027_ICC_RX_EN_A 0x0027
> +#define MAX98927_R0028_ICC_RX_EN_B 0x0028
> +#define MAX98927_R002B_ICC_TX_EN_A 0x002B
> +#define MAX98927_R002C_ICC_TX_EN_B 0x002C
> +#define MAX98927_R002E_ICC_HIZ_MANUAL_MODE 0x002E
> +#define MAX98927_R002F_ICC_TX_HIZ_EN_A 0x002F
> +#define MAX98927_R0030_ICC_TX_HIZ_EN_B 0x0030
> +#define MAX98927_R0031_ICC_LNK_EN 0x0031
> +#define MAX98927_R0032_PDM_TX_EN 0x0032
> +#define MAX98927_R0033_PDM_TX_HIZ_CTRL 0x0033
> +#define MAX98927_R0034_PDM_TX_CTRL 0x0034
> +#define MAX98927_R0035_PDM_RX_CTRL 0x0035
> +#define MAX98927_R0036_AMP_VOL_CTRL 0x0036
> +#define MAX98927_R0037_AMP_DSP_CFG 0x0037
> +#define MAX98927_R0038_TONE_GEN_DC_CFG 0x0038
> +#define MAX98927_R0039_DRE_CTRL 0x0039
> +#define MAX98927_R003A_AMP_EN 0x003A
> +#define MAX98927_R003B_SPK_SRC_SEL 0x003B
> +#define MAX98927_R003C_SPK_GAIN 0x003C
> +#define MAX98927_R003D_SSM_CFG 0x003D
> +#define MAX98927_R003E_MEAS_EN 0x003E
> +#define MAX98927_R003F_MEAS_DSP_CFG 0x003F
> +#define MAX98927_R0040_BOOST_CTRL0 0x0040
> +#define MAX98927_R0041_BOOST_CTRL3 0x0041
> +#define MAX98927_R0042_BOOST_CTRL1 0x0042
> +#define MAX98927_R0043_MEAS_ADC_CFG 0x0043
> +#define MAX98927_R0044_MEAS_ADC_BASE_MSB 0x0044
> +#define MAX98927_R0045_MEAS_ADC_BASE_LSB 0x0045
> +#define MAX98927_R0046_ADC_CH0_DIVIDE 0x0046
> +#define MAX98927_R0047_ADC_CH1_DIVIDE 0x0047
> +#define MAX98927_R0048_ADC_CH2_DIVIDE 0x0048
> +#define MAX98927_R0049_ADC_CH0_FILT_CFG 0x0049
> +#define MAX98927_R004A_ADC_CH1_FILT_CFG 0x004A
> +#define MAX98927_R004B_ADC_CH2_FILT_CFG 0x004B
> +#define MAX98927_R004C_MEAS_ADC_CH0_READ 0x004C
> +#define MAX98927_R004D_MEAS_ADC_CH1_READ 0x004D
> +#define MAX98927_R004E_MEAS_ADC_CH2_READ 0x004E
> +#define MAX98927_R0051_BROWNOUT_STATUS 0x0051
> +#define MAX98927_R0052_BROWNOUT_EN 0x0052
> +#define MAX98927_R0053_BROWNOUT_INFINITE_HOLD 0x0053
> +#define MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR 0x0054
> +#define MAX98927_R0055_BROWNOUT_LVL_HOLD 0x0055
> +#define MAX98927_R005A_BROWNOUT_LVL1_THRESH 0x005A
> +#define MAX98927_R005B_BROWNOUT_LVL2_THRESH 0x005B
> +#define MAX98927_R005C_BROWNOUT_LVL3_THRESH 0x005C
> +#define MAX98927_R005D_BROWNOUT_LVL4_THRESH 0x005D
> +#define MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS 0x005E
> +#define MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL 0x005F
> +#define MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL 0x0060
> +#define MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE 0x0061
> +#define MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT 0x0072
> +#define MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1 0x0073
> +#define MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2 0x0074
> +#define MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3 0x0075
> +#define MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT 0x0076
> +#define MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1 0x0077
> +#define MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2 0x0078
> +#define MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3 0x0079
> +#define MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT 0x007A
> +#define MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1 0x007B
> +#define MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2 0x007C
> +#define MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3 0x007D
> +#define MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT 0x007E
> +#define MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1 0x007F
> +#define MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2 0x0080
> +#define MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3 0x0081
> +#define MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM 0x0082
> +#define MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY 0x0083
> +#define MAX98927_R0084_ENV_TRACK_REL_RATE 0x0084
> +#define MAX98927_R0085_ENV_TRACK_HOLD_RATE 0x0085
> +#define MAX98927_R0086_ENV_TRACK_CTRL 0x0086
> +#define MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ 0x0087
> +#define MAX98927_R00FF_GLOBAL_SHDN 0x00FF
> +#define MAX98927_R0100_SOFT_RESET 0x0100
> +#define MAX98927_R01FF_REV_ID 0x01FF
> +
> +/* MAX98927_R0018_PCM_RX_EN_A */
> +#define MAX98927_PCM_RX_CH0_EN (0x1 << 0)
> +#define MAX98927_PCM_RX_CH1_EN (0x1 << 1)
> +#define MAX98927_PCM_RX_CH2_EN (0x1 << 2)
> +#define MAX98927_PCM_RX_CH3_EN (0x1 << 3)
> +#define MAX98927_PCM_RX_CH4_EN (0x1 << 4)
> +#define MAX98927_PCM_RX_CH5_EN (0x1 << 5)
> +#define MAX98927_PCM_RX_CH6_EN (0x1 << 6)
> +#define MAX98927_PCM_RX_CH7_EN (0x1 << 7)
> +
> +/* MAX98927_R001A_PCM_TX_EN_A */
> +#define MAX98927_PCM_TX_CH0_EN (0x1 << 0)
> +#define MAX98927_PCM_TX_CH1_EN (0x1 << 1)
> +#define MAX98927_PCM_TX_CH2_EN (0x1 << 2)
> +#define MAX98927_PCM_TX_CH3_EN (0x1 << 3)
> +#define MAX98927_PCM_TX_CH4_EN (0x1 << 4)
> +#define MAX98927_PCM_TX_CH5_EN (0x1 << 5)
> +#define MAX98927_PCM_TX_CH6_EN (0x1 << 6)
> +#define MAX98927_PCM_TX_CH7_EN (0x1 << 7)
> +
> +/* MAX98927_R001E_PCM_TX_CH_SRC_A */
> +#define MAX98927_PCM_TX_CH_SRC_A_V_SHIFT (0)
> +#define MAX98927_PCM_TX_CH_SRC_A_I_SHIFT (4)
> +
> +/* MAX98927_R001F_PCM_TX_CH_SRC_B */
> +#define MAX98927_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 5)
> +
> +/* MAX98927_R0020_PCM_MODE_CFG */
> +#define MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 2)
> +#define MAX98927_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
> +#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3)
> +#define MAX98927_PCM_FORMAT_I2S (0x0 << 0)
> +#define MAX98927_PCM_FORMAT_LJ (0x1 << 0)
> +
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
> +#define MAX98927_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
> +
> +/* MAX98927_R0021_PCM_MASTER_MODE */
> +#define MAX98927_PCM_MASTER_MODE_MASK (0x3 << 0)
> +#define MAX98927_PCM_MASTER_MODE_SLAVE (0x0 << 0)
> +#define MAX98927_PCM_MASTER_MODE_MASTER (0x3 << 0)
> +
> +#define MAX98927_PCM_MASTER_MODE_MCLK_MASK (0xF << 2)
> +#define MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT (2)
> +
> +/* MAX98927_R0022_PCM_CLK_SETUP */
> +#define MAX98927_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
> +
> +/* MAX98927_R0023_PCM_SR_SETUP1 */
> +#define MAX98927_PCM_SR_SET1_SR_MASK (0xF << 0)
> +
> +#define MAX98927_PCM_SR_SET1_SR_8000 (0x0 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_11025 (0x1 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_12000 (0x2 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_16000 (0x3 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_22050 (0x4 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_24000 (0x5 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_32000 (0x6 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_44100 (0x7 << 0)
> +#define MAX98927_PCM_SR_SET1_SR_48000 (0x8 << 0)
> +
> +/* MAX98927_R0024_PCM_SR_SETUP2 */
> +#define MAX98927_PCM_SR_SET2_SR_MASK (0xF << 4)
> +#define MAX98927_PCM_SR_SET2_SR_SHIFT (4)
> +#define MAX98927_PCM_SR_SET2_IVADC_SR_MASK (0xf << 0)
> +
> +/* MAX98927_R0025_PCM_TO_SPK_MONOMIX_A */
> +#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
> +#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
> +
> +/* MAX98927_R0035_PDM_RX_CTRL */
> +#define MAX98927_PDM_RX_EN_MASK (0x1 << 0)
> +
> +/* MAX98927_R0036_AMP_VOL_CTRL */
> +#define MAX98927_AMP_VOL_SEL (0x1 << 7)
> +#define MAX98927_AMP_VOL_SEL_WIDTH (1)
> +#define MAX98927_AMP_VOL_SEL_SHIFT (7)
> +#define MAX98927_AMP_VOL_MASK (0x7f << 0)
> +#define MAX98927_AMP_VOL_WIDTH (7)
> +#define MAX98927_AMP_VOL_SHIFT (0)
> +
> +/* MAX98927_R0037_AMP_DSP_CFG */
> +#define MAX98927_AMP_DSP_CFG_DCBLK_EN (0x1 << 0)
> +#define MAX98927_AMP_DSP_CFG_DITH_EN (0x1 << 1)
> +#define MAX98927_AMP_DSP_CFG_RMP_BYPASS (0x1 << 4)
> +#define MAX98927_AMP_DSP_CFG_DAC_INV (0x1 << 5)
> +#define MAX98927_AMP_DSP_CFG_RMP_SHIFT (4)
> +
> +/* MAX98927_R0039_DRE_CTRL */
> +#define MAX98927_DRE_CTRL_DRE_EN       (0x1 << 0)
> +#define MAX98927_DRE_EN_SHIFT 0x1
> +
> +/* MAX98927_R003A_AMP_EN */
> +#define MAX98927_AMP_EN_MASK (0x1 << 0)
> +
> +/* MAX98927_R003B_SPK_SRC_SEL */
> +#define MAX98927_SPK_SRC_MASK (0x3 << 0)
> +
> +/* MAX98927_R003C_SPK_GAIN */
> +#define MAX98927_SPK_PCM_GAIN_MASK (0x7 << 0)
> +#define MAX98927_SPK_PDM_GAIN_MASK (0x7 << 4)
> +#define MAX98927_SPK_GAIN_WIDTH (3)
> +
> +/* MAX98927_R003E_MEAS_EN */
> +#define MAX98927_MEAS_V_EN (0x1 << 0)
> +#define MAX98927_MEAS_I_EN (0x1 << 1)
> +
> +/* MAX98927_R0040_BOOST_CTRL0 */
> +#define MAX98927_BOOST_CTRL0_VOUT_MASK (0x1f << 0)
> +#define MAX98927_BOOST_CTRL0_PVDD_MASK (0x1 << 7)
> +#define MAX98927_BOOST_CTRL0_PVDD_EN_SHIFT (7)
> +
> +/* MAX98927_R0052_BROWNOUT_EN */
> +#define MAX98927_BROWNOUT_BDE_EN (0x1 << 0)
> +#define MAX98927_BROWNOUT_AMP_EN (0x1 << 1)
> +#define MAX98927_BROWNOUT_DSP_EN (0x1 << 2)
> +#define MAX98927_BROWNOUT_DSP_SHIFT (2)
> +
> +/* MAX98927_R0100_SOFT_RESET */
> +#define MAX98927_SOFT_RESET (0x1 << 0)
> +
> +/* MAX98927_R00FF_GLOBAL_SHDN */
> +#define MAX98927_GLOBAL_EN_MASK (0x1 << 0)
> +
> +struct max98927_priv {
> +       struct regmap *regmap;
> +       struct snd_soc_codec *codec;
> +       struct max98927_pdata *pdata;
> +       unsigned int spk_gain;
> +       unsigned int sysclk;
> +       unsigned int v_l_slot;
> +       unsigned int i_l_slot;
> +       bool interleave_mode;
> +       unsigned int ch_size;
> +       unsigned int rate;
> +       unsigned int iface;
> +       unsigned int master;
> +       unsigned int digital_gain;
> +};
> +#endif
> --
> 2.11.0
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/2] fpga: lattice machxo2: Add Lattice MachXO2 support
From: Alan Tull @ 2017-04-25 15:59 UTC (permalink / raw)
  To: Paolo Pisati
  Cc: Rob Herring, Mark Rutland, Alan Tull, Moritz Fischer,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-fpga-u79uwXL29TY76Z2rM5mHXA, linux-kernel
In-Reply-To: <1492960845-342-3-git-send-email-p.pisati-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Sun, Apr 23, 2017 at 10:20 AM, Paolo Pisati <p.pisati-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

Hi Paolo,

Thanks for submitting your driver.  A few things...

> Add support for the Lattice MachXO2 FPGA chip in Slave SPI configuration.
>

Please add a bit of a description here.  Format should be subject
line, skip a line,  description, skip a line, then your signoff.

> Signed-off-by: Paolo Pisati <p.pisati-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  drivers/fpga/Kconfig       |   7 ++
>  drivers/fpga/Makefile      |   1 +
>  drivers/fpga/machxo2-spi.c | 199 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 207 insertions(+)
>  create mode 100644 drivers/fpga/machxo2-spi.c
>
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index c81cb7d..cce135b 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -26,6 +26,13 @@ config FPGA_MGR_ICE40_SPI
>         help
>           FPGA manager driver support for Lattice iCE40 FPGAs over SPI.
>
> +config FPGA_MGR_MACHXO2_SPI
> +       tristate "Lattice MachXO2 SPI"
> +       depends on SPI
> +       help
> +        FPGA manager driver support for Lattice MachXO2 configuration
> +        over slave SPI interface.
> +
>  config FPGA_MGR_SOCFPGA
>         tristate "Altera SOCFPGA FPGA Manager"
>         depends on ARCH_SOCFPGA || COMPILE_TEST
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index c6f5d74..cdab1fe 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_FPGA)                      += fpga-mgr.o
>
>  # FPGA Manager Drivers
>  obj-$(CONFIG_FPGA_MGR_ICE40_SPI)       += ice40-spi.o
> +obj-$(CONFIG_FPGA_MGR_MACHXO2_SPI)     += machxo2-spi.o
>  obj-$(CONFIG_FPGA_MGR_SOCFPGA)         += socfpga.o
>  obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)     += socfpga-a10.o
>  obj-$(CONFIG_FPGA_MGR_TS73XX)          += ts73xx-fpga.o
> diff --git a/drivers/fpga/machxo2-spi.c b/drivers/fpga/machxo2-spi.c
> new file mode 100644
> index 0000000..5ee56bd
> --- /dev/null
> +++ b/drivers/fpga/machxo2-spi.c
> @@ -0,0 +1,199 @@
> +/**
> + * Lattice MachXO2 Slave SPI Driver
> + *
> + * Copyright (C) 2017 Paolo Pisati <p.pisati-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * Manage Lattice FPGA firmware that is loaded over SPI using
> + * the slave serial configuration interface.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/spi/spi.h>
> +
> +

Please run checkpatch and fix whatever it points out, such as not to
use double blank lines.

> +/* MachXO2 Programming Guide - sysCONFIG Programming Commands */
> +
> +#define ISC_ENABLE             0x000008c6
> +#define ISC_ERASE              0x0000040e
> +#define ISC_PROGRAMDONE                0x0000005e
> +#define LSC_CHECKBUSY          0x000000f0
> +#define LSC_INITADDRESS                0x00000046
> +#define LSC_PROGINCRNV         0x01000070
> +#define LSC_REFRESH            0x00000079
> +
> +/*
> + * Max CCLK in Slave SPI mode according to 'MachXO2 Family Data
> + * Sheet' sysCONFIG Port Timing Specifications (3-36)
> + */
> +#define MACHXO2_MAX_SPEED      66000000
> +
> +#define MACHXO2_LOW_DELAY      5       /* us */
> +#define MACHXO2_HIGH_DELAY     200     /* us */
> +
> +#define MACHXO2_OP_SIZE                sizeof(uint32_t)
> +#define MACHXO2_PAGE_SIZE      16
> +#define MACHXO2_BUF_SIZE       (MACHXO2_OP_SIZE + MACHXO2_PAGE_SIZE)
> +
> +
> +static int waituntilnotbusy(struct spi_device *spi)

Could you rename to something like wait_until_not_busy?

> +{
> +       uint8_t rx, busyflag = 0x80;

Please create a macro for the 0x80 value and use it here.

> +       uint32_t checkbusy = LSC_CHECKBUSY;

Another checkpatch: u32 is preferred over uint32_t.

> +
> +       do {
> +               if (spi_write_then_read(spi, &checkbusy, MACHXO2_OP_SIZE,
> +                                         &rx, sizeof(rx)))
> +                       return -EIO;

Please pass down the spi_write_then_read error code like:

ret = spi_write_then_read(...);
if (ret)
        return ret;

There's a few places below where I will point that out for spi_write as well.

> +       } while (rx & busyflag);

Skip a line before the return.

> +       return 0;
> +}
> +
> +static enum fpga_mgr_states machxo2_spi_state(struct fpga_manager *mgr)
> +{
> +       return FPGA_MGR_STATE_UNKNOWN;
> +}
> +
> +static int machxo2_write_init(struct fpga_manager *mgr,
> +                             struct fpga_image_info *info,
> +                             const char *buf, size_t count)
> +{
> +       struct spi_device *spi = mgr->priv;
> +       uint32_t enable = ISC_ENABLE;
> +       uint32_t erase = ISC_ERASE;
> +       uint32_t initaddr = LSC_INITADDRESS;
> +
> +       if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
> +               dev_err(&mgr->dev,
> +                       "Partial reconfiguration is not supported\n");
> +               return -ENOTSUPP;
> +       }
> +
> +       if (spi_write(spi, &enable, MACHXO2_OP_SIZE))
> +               goto fail;

Please skip a line here.

> +       udelay(MACHXO2_LOW_DELAY);
> +       if (spi_write(spi, &erase, MACHXO2_OP_SIZE))
> +               goto fail;

Again, it's better to pass the spi_write error code.

ret = spi_write(...)
if (ret)
     goto fail;

Then skip a line.

> +       waituntilnotbusy(spi);
> +       if (spi_write(spi, &initaddr, MACHXO2_OP_SIZE))
> +               goto fail;

Pass through the error code, same as above.

> +       return 0;
> +
> +fail:
> +       dev_err(&mgr->dev, "Error during FPGA init.\n");
> +       return -EIO;

return ret;

> +}
> +
> +static int machxo2_write(struct fpga_manager *mgr, const char *buf,
> +                        size_t count)
> +{
> +       struct spi_device *spi = mgr->priv;
> +       uint32_t progincr = LSC_PROGINCRNV;
> +       uint8_t payload[MACHXO2_BUF_SIZE];
> +       int i;
> +
> +       if (count % MACHXO2_PAGE_SIZE != 0) {
> +               dev_err(&mgr->dev, "Malformed payload.\n");
> +               return -EINVAL;
> +       }
> +
> +       memcpy(payload, &progincr, MACHXO2_OP_SIZE);
> +       for (i = 0; i < count; i += MACHXO2_PAGE_SIZE) {
> +               memcpy(&payload[MACHXO2_OP_SIZE], &buf[i], MACHXO2_PAGE_SIZE);
> +               if (spi_write(spi, payload, MACHXO2_BUF_SIZE)) {
> +                       dev_err(&mgr->dev, "Error loading the bitstream.\n");
> +                       return -EIO;

Pass through spi_write error code.

> +               }
> +               udelay(MACHXO2_HIGH_DELAY);
> +       }
> +
> +       return 0;
> +}
> +
> +static int machxo2_write_complete(struct fpga_manager *mgr,
> +                                 struct fpga_image_info *info)
> +{
> +       struct spi_device *spi = mgr->priv;
> +       uint32_t progdone = ISC_PROGRAMDONE;
> +       uint32_t refresh = LSC_REFRESH;
> +
> +       if (spi_write(spi, &progdone, MACHXO2_OP_SIZE))
> +               goto fail;

Pass spi_write error code if error.  And skip a line.

> +       /* yep, LSC_REFRESH is 3 bytes long actually */
> +       if (spi_write(spi, &refresh, MACHXO2_OP_SIZE-1))
> +               goto fail;

Here too.  Also add spaces around the minus sign.

> +       return 0;
> +
> +fail:
> +       dev_err(&mgr->dev, "Refresh failed.\n");
> +       return -EIO;

Will be return ret;

> +}
> +
> +static const struct fpga_manager_ops machxo2_ops = {
> +       .state = machxo2_spi_state,
> +       .write_init = machxo2_write_init,
> +       .write = machxo2_write,
> +       .write_complete = machxo2_write_complete,
> +};
> +
> +static int machxo2_spi_probe(struct spi_device *spi)
> +{
> +       struct device *dev = &spi->dev;
> +       int ret = 0;
> +
> +       if (spi->max_speed_hz > MACHXO2_MAX_SPEED) {
> +               dev_err(dev, "Speed is too high\n");
> +               return -EINVAL;
> +       }
> +
> +       ret =  fpga_mgr_register(dev, "Lattice MachXO2 SPI FPGA Manager",
> +                                &machxo2_ops, spi);
> +       if (ret)
> +               dev_err(dev, "Unable to register FPGA manager");

You can just 'return fpga_mgr_register(...);' here.

> +
> +       return ret;
> +}
> +
> +static int machxo2_spi_remove(struct spi_device *spi)
> +{
> +       struct device *dev = &spi->dev;
> +
> +       fpga_mgr_unregister(dev);

Skip  a line.

> +       return 0;
> +}
> +
> +static const struct of_device_id of_match[] = {
> +       { .compatible = "lattice,machxo2-slave-spi", },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, of_match);
> +
> +static const struct spi_device_id lattice_ids[] = {
> +       { "machxo2-slave-spi", 0 },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(spi, lattice_ids);
> +
> +static struct spi_driver machxo2_spi_driver = {
> +       .driver = {
> +               .name = "machxo2-slave-spi",
> +               .owner = THIS_MODULE,

You don't need to specify THIS_MODULE here.  spi_register_driver will
add that for you.

> +               .of_match_table = of_match_ptr(of_match),
> +       },
> +       .probe = machxo2_spi_probe,
> +       .remove = machxo2_spi_remove,
> +       .id_table = lattice_ids,
> +};
> +
> +module_spi_driver(machxo2_spi_driver)
> +
> +MODULE_AUTHOR("Paolo Pisati <p.pisati-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
> +MODULE_DESCRIPTION("Load Lattice FPGA firmware over SPI");
> +MODULE_LICENSE("GPL v2");
> --
> 2.7.4
>

Thanks,
Alan
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 15/18] dt-bindings: sound: Add bindings for Cirrus Logic Madera codecs
From: Mark Brown @ 2017-04-25 15:52 UTC (permalink / raw)
  To: Richard Fitzgerald
  Cc: gnurou, alsa-devel, jason, devicetree, linus.walleij, patches,
	linux-kernel, linux-gpio, robh+dt, tglx, lee.jones
In-Reply-To: <1493050124-5970-16-git-send-email-rf@opensource.wolfsonmicro.com>


[-- Attachment #1.1: Type: text/plain, Size: 1090 bytes --]

On Mon, Apr 24, 2017 at 05:08:41PM +0100, Richard Fitzgerald wrote:
> The Cirrus Logic Madera codecs are a family of related codecs with
> extensive digital and analogue I/O, digital mixing and routing,
> signal processing and programmable DSPs.

Please submit patches using subject lines reflecting the style for the
subsystem.  This makes it easier for people to identify relevant
patches.  Look at what existing commits in the area you're changing are
doing and make sure your subject lines visually resemble what they're
doing.

> +Required properties:
> +  - compatible : One of the following chip-specific strings:
> +        "cirrus,cs47l35-codec"
> +        "cirrus,cs47l85-codec"
> +        "cirrus,cs47l90-codec"

You shouldn't have compatible strings for subfunctions of a MFD unless
these represent meaningful reusable IPs that can exist separately from
the parent chip, that's clearly not the case here.  All you're doing
here is encoding Linux internal abstractions which aren't OS neutral and
might change in future (for example clocking might move more into the
clock API).

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Applied "spi-imx: Implements handling of the SPI_READY mode flag." to the spi tree
From: Mark Brown @ 2017-04-25 15:46 UTC (permalink / raw)
  To: Leif Middelschulte; +Cc: Leif Middelschulte, Mark Brown
In-Reply-To: <20170423191958.32724-1-Leif.Middelschulte-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

The patch

   spi-imx: Implements handling of the SPI_READY mode flag.

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From f72efa7e690ab5c4068ccba31c4da032bc45c29c Mon Sep 17 00:00:00 2001
From: Leif Middelschulte <leif.middelschulte-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date: Sun, 23 Apr 2017 21:19:58 +0200
Subject: [PATCH] spi-imx: Implements handling of the SPI_READY mode flag.

This patch implements consideration of the SPI_READY mode flag as
defined in spi.h. It extends the device tree bindings to support
the values defined by the reference manual for the DRCTL field.

Thus supporting edge-triggered and level-triggered bursts.

Signed-off-by: Leif Middelschulte <Leif.Middelschulte-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/spi/fsl-imx-cspi.txt         |  7 +++++++
 drivers/spi/spi-imx.c                                | 20 ++++++++++++++++++--
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
index 8bc95e2fc47f..31b5b21598ff 100644
--- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
+++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
@@ -23,6 +23,12 @@ See the clock consumer binding,
 Obsolete properties:
 - fsl,spi-num-chipselects : Contains the number of the chipselect
 
+Optional properties:
+- fsl,spi-rdy-drctl: Integer, representing the value of DRCTL, the register
+controlling the SPI_READY handling. Note that to enable the DRCTL consideration,
+the SPI_READY mode-flag needs to be set too.
+Valid values are: 0 (disabled), 1 (edge-triggered burst) and 2 (level-triggered burst).
+
 Example:
 
 ecspi@70010000 {
@@ -35,4 +41,5 @@ ecspi@70010000 {
 		   <&gpio3 25 0>; /* GPIO3_25 */
 	dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
 	dma-names = "rx", "tx";
+	fsl,spi-rdy-drctl = <1>;
 };
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 9a7c62f471dc..b402530a7a9a 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -95,6 +95,7 @@ struct spi_imx_data {
 	unsigned int spi_bus_clk;
 
 	unsigned int bytes_per_word;
+	unsigned int spi_drctl;
 
 	unsigned int count;
 	void (*tx)(struct spi_imx_data *);
@@ -246,6 +247,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_CTRL_XCH		(1 <<  2)
 #define MX51_ECSPI_CTRL_SMC		(1 << 3)
 #define MX51_ECSPI_CTRL_MODE_MASK	(0xf << 4)
+#define MX51_ECSPI_CTRL_DRCTL(drctl)	((drctl) << 16)
 #define MX51_ECSPI_CTRL_POSTDIV_OFFSET	8
 #define MX51_ECSPI_CTRL_PREDIV_OFFSET	12
 #define MX51_ECSPI_CTRL_CS(cs)		((cs) << 18)
@@ -355,6 +357,12 @@ static int mx51_ecspi_config(struct spi_device *spi,
 	 */
 	ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
 
+	/*
+	 * Enable SPI_RDY handling (falling edge/level triggered).
+	 */
+	if (spi->mode & SPI_READY)
+		ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
+
 	/* set clock speed */
 	ctrl |= mx51_ecspi_clkdiv(spi_imx, config->speed_hz, &clk);
 	spi_imx->spi_bus_clk = clk;
@@ -1173,7 +1181,7 @@ static int spi_imx_probe(struct platform_device *pdev)
 	struct spi_master *master;
 	struct spi_imx_data *spi_imx;
 	struct resource *res;
-	int i, ret, irq;
+	int i, ret, irq, spi_drctl;
 
 	if (!np && !mxc_platform_info) {
 		dev_err(&pdev->dev, "can't get the platform data\n");
@@ -1181,6 +1189,12 @@ static int spi_imx_probe(struct platform_device *pdev)
 	}
 
 	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
+	ret = of_property_read_u32(np, "fsl,spi-rdy-drctl", &spi_drctl);
+	if ((ret < 0) || (spi_drctl >= 0x3)) {
+		/* '11' is reserved */
+		spi_drctl = 0;
+	}
+
 	if (!master)
 		return -ENOMEM;
 
@@ -1216,7 +1230,9 @@ static int spi_imx_probe(struct platform_device *pdev)
 	spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
 	spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 	if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx))
-		spi_imx->bitbang.master->mode_bits |= SPI_LOOP;
+		spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY;
+
+	spi_imx->spi_drctl = spi_drctl;
 
 	init_completion(&spi_imx->xfer_done);
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH 2/2] ARM: dts: Add the ethernet and ethernet PHY to the cygnus core DT.
From: Jon Mason @ 2017-04-25 15:43 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Eric Anholt, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Network Development, Rob Herring, Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-arm-kernel, open list, BCM Kernel Feedback, Ray Jui,
	Scott Branden, Jon Mason
In-Reply-To: <44d0c48c-d80f-271e-0e19-ac87a53e2e53@cogentembedded.com>

On Tue, Apr 25, 2017 at 11:23 AM, Sergei Shtylyov
<sergei.shtylyov@cogentembedded.com> wrote:
> Hello!
>
> On 04/25/2017 06:15 PM, Jon Mason wrote:
>
>>>> Cygnus has a single amac controller connected to the B53 switch with 2
>>>> PHYs.  On the BCM911360_EP platform, those two PHYs are connected to
>>>> the external ethernet jacks.
>
>
> [...]
>
>>>> Signed-off-by: Eric Anholt <eric@anholt.net>
>>>> ---
>>>>  arch/arm/boot/dts/bcm-cygnus.dtsi      | 60
>>>> ++++++++++++++++++++++++++++++++++
>>>>  arch/arm/boot/dts/bcm911360_entphn.dts |  8 +++++
>>>>  2 files changed, 68 insertions(+)
>>>>
>>>> diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi
>>>> b/arch/arm/boot/dts/bcm-cygnus.dtsi
>>>> index 009f1346b817..318899df9972 100644
>>>> --- a/arch/arm/boot/dts/bcm-cygnus.dtsi
>>>> +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
>
> [...]
>>>>
>>>> @@ -295,6 +345,16 @@
>>>>                         status = "disabled";
>>>>                 };
>>>>
>>>> +               eth0: enet@18042000 {
>>>> +                       compatible = "brcm,amac";
>>>> +                       reg = <0x18042000 0x1000>,
>>>> +                             <0x18110000 0x1000>;
>>>> +                       reg-names = "amac_base", "idm_base";
>>>
>>>
>>>
>>>    I don't think "_base" suffixes are necessary here.
>>
>>
>> 100% necessary, per the driver.  See
>> drivers/net/ethernet/broadcom/bgmac-platform.c
>
>
>    I'd recommend to fix the driver/bindings then...

They're already in use in other device trees.  So, we'd need to
support backward compatibility on them, thus removing any real benefit
to changing them.


>
> MBR, Sergei
>

^ permalink raw reply

* [PATCH 3/3] drm/sun4i: backend: Clarify sun4i_backend_layer_enable debug message
From: Chen-Yu Tsai @ 2017-04-25 15:25 UTC (permalink / raw)
  To: Maxime Ripard, David Airlie, Rob Herring, Mark Rutland
  Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170425152505.6796-1-wens-jdAy2FN1RRM@public.gmane.org>

sun4i_backend_layer_enable can be called to enable or disable a layer.
However the debug message always says "Enable", which is confusing.

This patch makes the debug message vary according to the enable state.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index e9eca057ff35..e53107418add 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -73,7 +73,8 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 {
 	u32 val;
 
-	DRM_DEBUG_DRIVER("Enabling layer %d\n", layer);
+	DRM_DEBUG_DRIVER("%sabling layer %d\n", enable ? "En" : "Dis",
+			 layer);
 
 	if (enable)
 		val = SUN4I_BACKEND_MODCTL_LAY_EN(layer);
-- 
2.11.0

^ permalink raw reply related

* [PATCH 2/3] drm/sun4i: Set TCON clock inside sun4i_tconX_mode_set
From: Chen-Yu Tsai @ 2017-04-25 15:25 UTC (permalink / raw)
  To: Maxime Ripard, David Airlie, Rob Herring, Mark Rutland
  Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170425152505.6796-1-wens-jdAy2FN1RRM@public.gmane.org>

Currently we are configuring the TCON's dot clock or special clock
directly from the encoder mode_set functions. Since we already
provide mode_set helper functions for the TCON's 2 channels, we
can set the respective clock from those helpers, and reduce the
exposure of the TCON's internals.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 drivers/gpu/drm/sun4i/sun4i_rgb.c  | 2 --
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++++
 drivers/gpu/drm/sun4i/sun4i_tv.c   | 2 --
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index 1147451eb993..51ece4c39d7e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -175,8 +175,6 @@ static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
 
 	sun4i_tcon0_mode_set(tcon, mode);
 
-	clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
-
 	/* FIXME: This seems to be board specific */
 	clk_set_phase(tcon->dclk, 120);
 }
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 8301389c411d..29fd829aa54c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -131,6 +131,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 	u8 clk_delay;
 	u32 val = 0;
 
+	/* Configure the dot clock */
+	clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
+
 	/* Adjust clock delay */
 	clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
 	regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
@@ -206,6 +209,9 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 
 	WARN_ON(!tcon->quirks->has_channel_1);
 
+	/* Configure the dot clock */
+	clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+
 	/* Adjust clock delay */
 	clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
 	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 49c49431a053..542da220818b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -486,8 +486,6 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
 		      SUN4I_TVE_RESYNC_FIELD : 0));
 
 	regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0);
-
-	clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
 }
 
 static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
-- 
2.11.0

^ permalink raw reply related

* [PATCH 1/3] drm/sun4i: Drop unused tcon pointer
From: Chen-Yu Tsai @ 2017-04-25 15:25 UTC (permalink / raw)
  To: Maxime Ripard, David Airlie, Rob Herring, Mark Rutland
  Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20170425152505.6796-1-wens-jdAy2FN1RRM@public.gmane.org>

The sun4i DRM driver now uses 2 lists to track backends and tcons.
During the switch, the original tcon pointer was not removed.

As it is now unused, remove it, so other new drivers can't accidentally
use it.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---

As mentioned in the cover letter, please squash this into the patch

    drm/sun4i: Use lists to track registered display backends and TCONs

---
 drivers/gpu/drm/sun4i/sun4i_drv.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index 835bdb5cc0c2..250c29017ef5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -20,7 +20,6 @@
 struct sun4i_drv {
 	struct list_head	backend_list;
 	struct list_head	tcon_list;
-	struct sun4i_tcon	*tcon;
 
 	struct drm_fbdev_cma	*fbdev;
 };
-- 
2.11.0

^ permalink raw reply related

* [PATCH 0/3] drm/sun4i: More cleanups and fixes
From: Chen-Yu Tsai @ 2017-04-25 15:25 UTC (permalink / raw)
  To: Maxime Ripard, David Airlie, Rob Herring, Mark Rutland
  Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw

Hi Maxime,

The subject is probably getting old. Here are a few more cleanups.

Patch 1 should have been part of the patch

    drm/sun4i: Use lists to track registered display backends and TCONs

from my multiple pipeline support series. Please squash it in if you can.

Patch 2 just moves setting the TCON clocks back inside the TCON driver.

Patch 3 cleans up a DRM driver debug message.

Regards
ChenYu


Chen-Yu Tsai (3):
  drm/sun4i: Drop unused tcon pointer
  drm/sun4i: Set TCON clock inside sun4i_tconX_mode_set
  drm/sun4i: backend: Clarify sun4i_backend_layer_enable debug message

 drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++-
 drivers/gpu/drm/sun4i/sun4i_drv.h     | 1 -
 drivers/gpu/drm/sun4i/sun4i_rgb.c     | 2 --
 drivers/gpu/drm/sun4i/sun4i_tcon.c    | 6 ++++++
 drivers/gpu/drm/sun4i/sun4i_tv.c      | 2 --
 5 files changed, 8 insertions(+), 6 deletions(-)

-- 
2.11.0

^ permalink raw reply

* Re: [PATCH 2/2] ARM: dts: Add the ethernet and ethernet PHY to the cygnus core DT.
From: Sergei Shtylyov @ 2017-04-25 15:23 UTC (permalink / raw)
  To: Jon Mason
  Cc: Mark Rutland, Andrew Lunn, Florian Fainelli, Scott Branden,
	Vivien Didelot, Jon Mason, Network Development, open list,
	Eric Anholt,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Rob Herring, BCM Kernel Feedback, Ray Jui, linux-arm-kernel
In-Reply-To: <CAC3K-4qn5oCXvyMCkFESGqMHqHXGiNUW6wfRx2LUZ8qZ39qroQ@mail.gmail.com>

Hello!

On 04/25/2017 06:15 PM, Jon Mason wrote:

>>> Cygnus has a single amac controller connected to the B53 switch with 2
>>> PHYs.  On the BCM911360_EP platform, those two PHYs are connected to
>>> the external ethernet jacks.

[...]

>>> Signed-off-by: Eric Anholt <eric@anholt.net>
>>> ---
>>>  arch/arm/boot/dts/bcm-cygnus.dtsi      | 60
>>> ++++++++++++++++++++++++++++++++++
>>>  arch/arm/boot/dts/bcm911360_entphn.dts |  8 +++++
>>>  2 files changed, 68 insertions(+)
>>>
>>> diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi
>>> b/arch/arm/boot/dts/bcm-cygnus.dtsi
>>> index 009f1346b817..318899df9972 100644
>>> --- a/arch/arm/boot/dts/bcm-cygnus.dtsi
>>> +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
[...]
>>> @@ -295,6 +345,16 @@
>>>                         status = "disabled";
>>>                 };
>>>
>>> +               eth0: enet@18042000 {
>>> +                       compatible = "brcm,amac";
>>> +                       reg = <0x18042000 0x1000>,
>>> +                             <0x18110000 0x1000>;
>>> +                       reg-names = "amac_base", "idm_base";
>>
>>
>>    I don't think "_base" suffixes are necessary here.
>
> 100% necessary, per the driver.  See
> drivers/net/ethernet/broadcom/bgmac-platform.c

    I'd recommend to fix the driver/bindings then...

MBR, Sergei

^ permalink raw reply

* Re: [PATCH v2 2/2] dmaengine: Add DW AXI DMAC driver
From: Eugeniy Paltsev @ 2017-04-25 15:16 UTC (permalink / raw)
  To: andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org
  Cc: vinod.koul-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	Alexey.Brodkin-HKixBCOQz3hWk0Htik3J/w@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Eugeniy.Paltsev-HKixBCOQz3hWk0Htik3J/w@public.gmane.org,
	linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
	dmaengine-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1493052970.24567.168.camel-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 12167 bytes --]

On Mon, 2017-04-24 at 19:56 +0300, Andy Shevchenko wrote:
> On Mon, 2017-04-24 at 15:55 +0000, Eugeniy Paltsev wrote:
> > Hi,
> > On Fri, 2017-04-21 at 18:13 +0300, Andy Shevchenko wrote:
> > > On Fri, 2017-04-21 at 14:29 +0000, Eugeniy Paltsev wrote:
> > > > On Tue, 2017-04-18 at 15:31 +0300, Andy Shevchenko wrote:
> > > > > On Fri, 2017-04-07 at 17:04 +0300, Eugeniy Paltsev wrote:
> > > > > > This patch adds support for the DW AXI DMAC controller.
> > > > > > +static inline void
> > > > > > +axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32
> > > > > > val)
> > > > > > +{
> > > > > > +	iowrite32(val, chip->regs + reg);
> > > > >
> > > > > Are you going to use IO ports for this IP? I don't think so.
> > > > > Wouldn't be better to call readl()/writel() instead?
> > > >
> > > > As I understand, it's better to use ioread/iowrite as more
> > > > universal
> > > > IO
> > > > access way. Am I wrong?
> > >
> > > As I said above the ioreadX/iowriteX makes only sense when your
> > > IP
> > > would be accessed via IO region or MMIO. I'm pretty sure IO is
> > > not
> > > the case at all for this IP.
> >
> > MMIO? This IP works exactly via memory-mapped I/O.
>
> Yes, and why do you need to check this on each IO read/write?
> Please, switch to plain readX()/writeX() instead.
Ok, I'll switch to readX()/writeX().

> > > > > > +		val = axi_chan_ioread32(chan,
> > > > > > CH_INTSTATUS_ENA);
> > > > > > +		val &= ~irq_mask;
> > > > > > +		axi_chan_iowrite32(chan, CH_INTSTATUS_ENA,
> > > > > > val);
> > > > > > +	}
> > > > > > +
> > > > > > +	return min_t(size_t, __ffs(sdl), max_width);
> > > > > > +}
> > > > > > +static void axi_desc_put(struct axi_dma_desc *desc)
> > > > > > +{
> > > > > > +	struct axi_dma_chan *chan = desc->chan;
> > > > > > +	struct dw_axi_dma *dw = chan->chip->dw;
> > > > > > +	struct axi_dma_desc *child, *_next;
> > > > > > +	unsigned int descs_put = 0;
> > > > > > +	list_for_each_entry_safe(child, _next, &desc-
> > > > > > > xfer_list,
> > > > > >
> > > > > > xfer_list) {
> > > > >
> > > > > xfer_list looks redundant.
> > > > > Can you elaborate why virtual channel management is not
> > > > > working
> > > > > for
> > > > > you?
> > > >
> > > > Each virtual descriptor encapsulates several hardware
> > > > descriptors,
> > > > which belong to same transfer.
> > > > This list (xfer_list) is used only for allocating/freeing these
> > > > descriptors and it doesn't affect on virtual dma work logic.
> > > > I can see this approach in several drivers with VirtDMA (but
> > > > they
> > > > mostly use array instead of list)
> > >
> > > You described how most of the DMA drivers are implemented, though
> > > they
> > > are using just sg_list directly. I would recommend to do the same
> > > and
> > > get rid of this list.
> >
> > This IP can be (ans is) configured with small block size.
> > (note, that I am not saying about runtime HW configuration)
> >
> > And there is opportunity what we can't use sg_list directly and
> > need
> > to
> > split sg_list to a smaller chunks.
>
> That's what I have referred quite ago. The driver should provide an
> interface to tell potential caller what maximum block (number of
> items
> with given bus width) it supports.
>
> We have struct dma_parms in struct device, but what we actually need
> is
> to support similar on per channel basis in DMAengine framework.
>
> So, instead of working around this I recommend either to implement it
> properly or rely on the fact that in the future someone eventually
> does that for you.
>
> Each driver which has this re-splitting mechanism should be cleaned
> up and refactored.
I still can't see any pros of this implementation.
There is no performance profit: we anyway need to re-splitt sg_list
(but now in dma-user driver instead of dma driver)

If we want to use same descriptors several times we just can use
DMA_CTRL_REUSE option - the descriptors will be created one time and
re-splitting will be сompleted only one time.

But there are cons of this implementation:
we need to implement re-splitting mechanism in each place we use dma
instead of one dma driver. So there are more places for bugs and etc...

> > > > > Btw, are you planning to use priority at all? For now on I
> > > > > didn't
> > > > > see
> > > > > a single driver (from the set I have checked, like 4-5 of
> > > > > them)
> > > > > that
> > > > > uses priority anyhow. It makes driver more complex for
> > > > > nothing.
> > > >
> > > > Only for dma slave operations.
> > >
> > > So, in other words you *have* an actual two or more users that
> > > *need*
> > > prioritization?
> >
> > As I remember there was an idea to give higher priority to audio
> > dma
> > chanels.
>
> I don't see cyclic transfers support in the driver. So, I would
> suggest
> just drop entire prioritization for now. When it would be actual user
> one may start thinking of it.
> Just a rule of common sense: do not implement something which will
> have no user or solve non-existing problem.

Ok, I'll drop prioritization untill I implement cyclic transfers.

> > > > > As I said earlier dw_dmac is *bad* example of the (virtual
> > > > > channel
> > > > > based) DMA driver.
> > > > >
> > > > > I guess you may just fail the descriptor and don't pretend it
> > > > > has
> > > > > been processed successfully.
> > > >
> > > > What do you mean by saying "fail the descriptor"?
> > > > After I get error I cancel current transfer and free all
> > > > descriptors
> > > > from it (by calling vchan_cookie_complete).
> > > > I can't store error status in descriptor structure because it
> > > > will
> > > > be
> > > > freed by vchan_cookie_complete.
> > > > I can't store error status in channel structure because it will
> > > > be
> > > > overwritten by next transfer.
> > >
> > > Better not to pretend that it has been processed successfully.
> > > Don't
> > > call callback on it and set its status to DMA_ERROR (that's why
> > > descriptors in many drivers have dma_status field). When user
> > > asks for
> > > status (using cookie) the saved value would be returned until
> > > descriptor
> > > is active.
> > >
> > > Do you have some other workflow in mind?
> >
> > Hmm...
> > Do you mean I should left error descriptors in desc_issued list
> > or I should create another list (like desc_error) in my driver and
> > move
> > error descriptors to desc_error list?
> >
> > And when exactly should I free error descriptors?
> See below.
>
> > I checked hsu/hsu.c dma driver implementation:
> >   vdma descriptor is deleted from desc_issued list when transfer
> >   starts. When descriptor marked as error descriptor
> >   vchan_cookie_complete isn't called for this descriptor. And this
> >   descriptor isn't placed in any list. So error descriptors *never*
> >   will be freed.
> >   I don't actually like this approach.
>
> Descriptor is active until terminate_all() is called or new
> descriptor
> is supplied. So, the caller has a quite time to check on it.
>
> So, what's wrong on it by your opinion?

Hmm, this looks OK. (In my example (hsu/hsu.c driver) error descriptors
are not freed even after terminate_all is called)

> Of course, if you want to keep by some reason (should be stated what
> the reason in comment) erred descriptors, you can do that.

So, I'll create desc_error list and store failed descriptors in this
list until terminate_all() is called.
Is it OK implementation?

> > > > > > +static const struct dev_pm_ops dw_axi_dma_pm_ops = {
> > > > > > +	SET_RUNTIME_PM_OPS(axi_dma_runtime_suspend,
> > > > > > axi_dma_runtime_resume, NULL)
> > > > > > +};
> > > > >
> > > > > Have you tried to build with CONFIG_PM disabled?
> > > >
> > > > Yes.
> > > >
> > > > > I'm pretty sure you need __maybe_unused applied to your PM
> > > > > ops.
> > > >
> > > > I call axi_dma_runtime_suspend / axi_dma_runtime_resume even I
> > > > dont't
> > > > use PM.
> > > > (I call them in probe / remove function.)
> > >
> > > Hmm... I didn't check your ->probe() and ->remove(). Do you mean
> > > you
> > > call them explicitly by those names?
> > >
> > > If so, please don't do that. Use pm_runtime_*() instead. And...
> > >
> > > > So I don't need to declare them with __maybe_unused.
> > >
> > > ...in that case it's possible you have them defined but not used.
> > >
> >
> > From my ->probe() function:
> >
> > pm_runtime_get_noresume(chip->dev);
> > ret = axi_dma_runtime_resume(chip->dev);
> >
> > Firstly I only incrememt counter.
> > Secondly explicitly call my resume function.
> >
> > I call them explicitly because I need driver to work also without
> > Runtime PM. So I can't just call pm_runtime_get here instead of
> > pm_runtime_get_noresume + axi_dma_runtime_resume.
> >
> > Of course I can copy *all* code from axi_dma_runtime_resume
> > to ->probe() function, but I don't really like this idea.
>
> It looks like you need more time to investigate how runtime PM works
> from driver point of view, but you shouldn't call your PM callbacks
> directly without a really good reason (weird silicon bugs,
> architectural impediments). I don't think that is the case here.
>
There is a simple reason:
I had to do same actions in probe/remove as in
runtime_resume/runtime_suspend.
(like enabling clock, enabling dma)

If my driver is build with RUNTIME_PM this actions will be
automatically handled by runtime pm (clock and dma will be enabled
before using and disabled after using).
Otherwise, if my driver is build without RUNTIME_PM clock and dma will
be enabled only one time - when ->probe() is called.
So I use runtime_resume callback directly for this purpose (because if
my driver is build without RUNTIME_PM this callback wiil not be called
at all)

> > > > > > +	bool		is_paused;
> > > > >
> > > > > I still didn't get (already forgot) why you can't use
> > > > > dma_status
> > > > > instead for the active descriptor?
> > > >
> > > > As I said before, I checked several driver, which have status
> > > > variable
> > > > in their channel structure - it is used *only* for
> > > > determinating
> > > > is
> > > > channel paused or not. So there is no much sense in replacing
> > > > "is_paused" to "status" and I left "is_paused" variable
> > > > untouched.
> > >
> > > Not only (see above), the errored descriptor keeps that status.
> > >
> > > > (I described above why we can't use status in channel structure
> > > > for
> > > > error handling)
> > >
> > > Ah, I'm talking about descriptor.
> >
> > Again - PAUSED is per-channel flag. So, even if we have status
> > field
> > in
> > each descriptor, it is simpler to use one per-channel flag instead
> > of
> > plenty per-descriptor flags.
> > When we pausing/resuming dma channel it is simpler to set only one
> > flag
> > instead of writing DMA_PAUSED to *each* descriptor status field.
>
> What do you mean by "each"? I don't recall the driver which can
> handle
> more than one *active* descriptor per channel. Do you?
>
> In that case status of active descriptor == status of channel. That
> trick (I also already referred to earlier) is used in some drivers.

Ok, I'll recheck others implementation.

> > > I mean, who are the users of them? If it's only one module, there
> > > is
> > > no need to put them in header.
> >
> > Yes, only one module.
> > Should I move all this definitions to axi_dma_platform.c file and
> > rid
> > of both axi_dma_platform_reg.h and axi_dma_platform.h headers?
> Depends on your design.
>
> If it would be just one C module it might make sense to use driver.c
> and driver.h or just driver.c.
> I see several drivers in current linux-next that are using latter and
> some that are using former, and number of plain driver.c variant is
> bigger.

Ok.

--
 Eugeniy PaltsevN‹§²æìr¸›yúèšØb²X¬¶Ç§vØ^–)Þº{.nÇ+‰·zøœzÚÞz)í…æèw*\x1fjg¬±¨\x1e¶‰šŽŠÝ¢j.ïÛ°\½½MŽúgjÌæa×\x02››–' ™©Þ¢¸\f¢·¦j:+v‰¨ŠwèjØm¶Ÿÿ¾\a«‘êçzZ+ƒùšŽŠÝ¢j"ú!¶i

^ permalink raw reply

* Re: [PATCH 2/2] ARM: dts: Add the ethernet and ethernet PHY to the cygnus core DT.
From: Jon Mason @ 2017-04-25 15:15 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Eric Anholt, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Network Development, Rob Herring, Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-arm-kernel, open list, BCM Kernel Feedback, Ray Jui,
	Scott Branden, Jon Mason
In-Reply-To: <f870339f-2fa1-411d-5ce8-adbe8802d8a8-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

On Tue, Apr 25, 2017 at 5:40 AM, Sergei Shtylyov
<sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> wrote:
> Hello.
>
> On 4/25/2017 12:50 AM, Eric Anholt wrote:
>
>> Cygnus has a single amac controller connected to the B53 switch with 2
>> PHYs.  On the BCM911360_EP platform, those two PHYs are connected to
>> the external ethernet jacks.
>
>
>    My spell checker trips on "amac" and "ethernet" -- perhaps they need
> capitalization?
>
>> Signed-off-by: Eric Anholt <eric-WhKQ6XTQaPysTnJN9+BGXg@public.gmane.org>
>> ---
>>  arch/arm/boot/dts/bcm-cygnus.dtsi      | 60
>> ++++++++++++++++++++++++++++++++++
>>  arch/arm/boot/dts/bcm911360_entphn.dts |  8 +++++
>>  2 files changed, 68 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi
>> b/arch/arm/boot/dts/bcm-cygnus.dtsi
>> index 009f1346b817..318899df9972 100644
>> --- a/arch/arm/boot/dts/bcm-cygnus.dtsi
>> +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
>> @@ -142,6 +142,56 @@
>>                         interrupts = <0>;
>>                 };
>>
>> +               mdio: mdio@18002000 {
>> +                       compatible = "brcm,iproc-mdio";
>> +                       reg = <0x18002000 0x8>;
>> +                       #size-cells = <1>;
>> +                       #address-cells = <0>;
>> +
>> +                       gphy0: eth-gphy@0 {
>
>
>    The node anmes must be generic, the DT spec has standardized
> "ethernet-phy" name for this case.
>
>> +                               reg = <0>;
>> +                               max-speed = <1000>;
>> +                       };
>> +
>> +                       gphy1: eth-gphy@1 {
>> +                               reg = <1>;
>> +                               max-speed = <1000>;
>> +                       };
>> +               };
>
> [...]
>>
>> @@ -295,6 +345,16 @@
>>                         status = "disabled";
>>                 };
>>
>> +               eth0: enet@18042000 {
>> +                       compatible = "brcm,amac";
>> +                       reg = <0x18042000 0x1000>,
>> +                             <0x18110000 0x1000>;
>> +                       reg-names = "amac_base", "idm_base";
>
>
>    I don't think "_base" suffixes are necessary here.

100% necessary, per the driver.  See
drivers/net/ethernet/broadcom/bgmac-platform.c


>
> [...]
>
> MBR, Sergei
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes
From: Peter Rosin @ 2017-04-25 14:55 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Jonathan Cameron, linux-kernel, Greg Kroah-Hartman, Wolfram Sang,
	Rob Herring, Mark Rutland, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Jonathan Corbet, linux-i2c, devicetree,
	linux-iio, linux-doc, Andrew Morton, Colin Ian King,
	Paul Gortmaker, kernel
In-Reply-To: <f74d5619-8614-d003-3c70-710aee0b550b@axentia.se>

On 2017-04-25 16:16, Peter Rosin wrote:
> On 2017-04-24 16:59, Philipp Zabel wrote:
>> On Mon, 2017-04-24 at 16:36 +0200, Peter Rosin wrote:
>> [...]
>>>> How about an atomic use_count on the mux_control, a bool shared that is
>>>> only set by the first consumer, and controls whether selecting locks?
>>>
>>> That has the drawback that it is hard to restore the mux-control in a safe
>>> way so that exclusive consumers are allowed after the last shared consumer
>>> puts the mux away.
>>
>> True.
>>
>>> Agreed, it's a corner case, but I had this very similar
>>> patch going through the compiler when I got this mail. Does it work as well
>>> as what you suggested?
>>
>> Yes, this patch works just as well.
> 
> Right, as expected :-) However, I don't like it much. It divides the mux
> consumers into two camps in a way that makes it difficult to select which
> camp a consumer should be in.
> 
> E.g. consider the iio-mux. The current implementation only supports quick
> accesses that fit the mux_control_get_shared case. But if that mux in the
> future needs to grow continuous buffered accesses, I think there will be
> pressure to switch it over to the exclusive mode. Because that is a lot
> closer to what you are doing with the video-mux. And then what? It will be
> impossible to predict if the end user is going to use buffered accesses or
> not...
> 
> So, I think the best approach is to skip the distinction between shared
> and exclusive consumers and instead implement the locking with an ordinary
> semaphore (instead of the old rwsem or the current mutex). Semaphores don't
> have the property that the same task should down/up them (mutexes require
> that for lock/unlock, and is also the reason for the lockdep complaint) and
> thus fits better for long-time use such as yours or the above iio-mux with
> buffered accesses. It should also hopefully be cheaper that an rwsem, and
> not have any downgrade_write calls thus possibly keeping Greg sufficiently
> happy...
> 
> Sure, consumers can still dig themselves into a hole by not calling deselect
> as they should, but at least I think it can be made to work w/o dividing the
> consumers...

Like this (only compile-tested). Philipp, it should work the same as with
the rwsem in v13 and earlier. At least for your case...

Cheers,
peda

diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index c02fa4dd2d09..f99b70d4e319 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -116,7 +116,7 @@ struct mux_chip *mux_chip_alloc(struct device *dev,
                struct mux_control *mux = &mux_chip->mux[i];

                mux->chip = mux_chip;
-               mutex_init(&mux->lock);
+               sema_init(&mux->lock, 1);
                mux->cached_state = MUX_CACHE_UNKNOWN;
                mux->idle_state = MUX_IDLE_AS_IS;
        }
@@ -372,12 +372,14 @@ int mux_control_select(struct mux_control *mux, unsigned int state)
 {
        int ret;

-       mutex_lock(&mux->lock);
+       ret = down_killable(&mux->lock);
+       if (ret < 0)
+               return ret;

        ret = __mux_control_select(mux, state);

        if (ret < 0)
-               mutex_unlock(&mux->lock);
+               up(&mux->lock);

        return ret;
 }
@@ -399,13 +401,13 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state)
 {
        int ret;

-       if (!mutex_trylock(&mux->lock))
+       if (down_trylock(&mux->lock))
                return -EBUSY;

        ret = __mux_control_select(mux, state);

        if (ret < 0)
-               mutex_unlock(&mux->lock);
+               up(&mux->lock);

        return ret;
 }
@@ -427,7 +429,7 @@ int mux_control_deselect(struct mux_control *mux)
            mux->idle_state != mux->cached_state)
                ret = mux_control_set(mux, mux->idle_state);

-       mutex_unlock(&mux->lock);
+       up(&mux->lock);

        return ret;
 }
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 95269f40670a..43f65f80c275 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -15,7 +15,6 @@

 #include <dt-bindings/mux/mux.h>
 #include <linux/device.h>
-#include <linux/mutex.h>
 #include <linux/semaphore.h>

 struct mux_chip;
@@ -44,7 +43,7 @@ struct mux_control_ops {
  * mux drivers.
  */
 struct mux_control {
-       struct mutex lock; /* protects the state of the mux */
+       struct semaphore lock; /* protects the state of the mux */

        struct mux_chip *chip;
        int cached_state;



^ permalink raw reply related

* Re: [PATCH v2 12/18] gpio: madera: Support Cirrus Logic Madera class codecs
From: Richard Fitzgerald @ 2017-04-25 14:44 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, alsa-devel@alsa-project.org, Jason Cooper,
	devicetree@vger.kernel.org,
	open list:WOLFSON MICROELECTRONICS DRIVERS,
	linux-kernel@vger.kernel.org, Rob Herring,
	linux-gpio@vger.kernel.org, Mark Brown, Thomas Gleixner,
	Lee Jones
In-Reply-To: <CACRpkdbhgkwtPygfRL6JXc7syi4MqSUXx2jrVzp7q9FPOWX6OQ@mail.gmail.com>

On Tue, 2017-04-25 at 16:13 +0200, Linus Walleij wrote:
> On Mon, Apr 24, 2017 at 6:08 PM, Richard Fitzgerald
> <rf@opensource.wolfsonmicro.com> wrote:
> 
> > This adds support for the GPIOs on Cirrus Logic Madera class codecs.
> > Any pins not used for special functions (see the pinctrl driver) can be
> > used as general single-bit input or output lines. The number of available
> > GPIOs varies between codecs.
> >
> > Signed-off-by: Nariman Poushin <nariman@opensource.wolfsonmicro.com>
> > Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
> > Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> > ---
> > Changes from V1:
> > - dt bindings moved to a separate patch
> > - dependent on pinctrl driver instead of parent MFD
> > - added get_direction function
> > - added .request / .free / .set_config to work with pinctrl driver
> > - register range with pinctrl driver
> 
> Nice, but...
> 
> > +       ret = gpiochip_add_pin_range(&madera_gpio->gpio_chip, "madera-pinctrl",
> > +                                    0, 0, madera_gpio->gpio_chip.ngpio);
> > +       if (ret) {
> > +               dev_warn(&pdev->dev, "Failed to add pin range (%d)\n", ret);
> > +               return ret;
> > +       }
> 
> This is all fine, but we have generic code for adding ranges from
> the device tree, see
> Documentation/devicetree/bindings/gpio/gpio.txt
> 

The range of gpio pins is a fixed property of the chip, and so is the
combination of gpio+pinctrl drivers.

I think the general principle of the DT maintainers is that DT should be
used for things that the drivers don't already know and can't figure
out.

> With that this range should not even be needed.
> Apart from that it looks pretty solid.
> 
> Yours,
> Linus Walleij

^ permalink raw reply

* Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes
From: Peter Rosin @ 2017-04-25 14:16 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Jonathan Cameron, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Greg Kroah-Hartman, Wolfram Sang, Rob Herring, Mark Rutland,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	Jonathan Corbet, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Colin Ian King,
	Paul Gortmaker, kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <1493045969.2446.47.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

On 2017-04-24 16:59, Philipp Zabel wrote:
> On Mon, 2017-04-24 at 16:36 +0200, Peter Rosin wrote:
> [...]
>>> How about an atomic use_count on the mux_control, a bool shared that is
>>> only set by the first consumer, and controls whether selecting locks?
>>
>> That has the drawback that it is hard to restore the mux-control in a safe
>> way so that exclusive consumers are allowed after the last shared consumer
>> puts the mux away.
> 
> True.
> 
>> Agreed, it's a corner case, but I had this very similar
>> patch going through the compiler when I got this mail. Does it work as well
>> as what you suggested?
> 
> Yes, this patch works just as well.

Right, as expected :-) However, I don't like it much. It divides the mux
consumers into two camps in a way that makes it difficult to select which
camp a consumer should be in.

E.g. consider the iio-mux. The current implementation only supports quick
accesses that fit the mux_control_get_shared case. But if that mux in the
future needs to grow continuous buffered accesses, I think there will be
pressure to switch it over to the exclusive mode. Because that is a lot
closer to what you are doing with the video-mux. And then what? It will be
impossible to predict if the end user is going to use buffered accesses or
not...

So, I think the best approach is to skip the distinction between shared
and exclusive consumers and instead implement the locking with an ordinary
semaphore (instead of the old rwsem or the current mutex). Semaphores don't
have the property that the same task should down/up them (mutexes require
that for lock/unlock, and is also the reason for the lockdep complaint) and
thus fits better for long-time use such as yours or the above iio-mux with
buffered accesses. It should also hopefully be cheaper that an rwsem, and
not have any downgrade_write calls thus possibly keeping Greg sufficiently
happy...

Sure, consumers can still dig themselves into a hole by not calling deselect
as they should, but at least I think it can be made to work w/o dividing the
consumers...

Cheers,
peda

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 12/18] gpio: madera: Support Cirrus Logic Madera class codecs
From: Linus Walleij @ 2017-04-25 14:13 UTC (permalink / raw)
  To: Richard Fitzgerald
  Cc: Lee Jones, Mark Brown, Alexandre Courbot, Rob Herring,
	Thomas Gleixner, Jason Cooper,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org,
	open list:WOLFSON MICROELECTRONICS DRIVERS,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1493050124-5970-13-git-send-email-rf-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>

On Mon, Apr 24, 2017 at 6:08 PM, Richard Fitzgerald
<rf-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org> wrote:

> This adds support for the GPIOs on Cirrus Logic Madera class codecs.
> Any pins not used for special functions (see the pinctrl driver) can be
> used as general single-bit input or output lines. The number of available
> GPIOs varies between codecs.
>
> Signed-off-by: Nariman Poushin <nariman-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
> Signed-off-by: Richard Fitzgerald <rf-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
> Signed-off-by: Charles Keepax <ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org>
> ---
> Changes from V1:
> - dt bindings moved to a separate patch
> - dependent on pinctrl driver instead of parent MFD
> - added get_direction function
> - added .request / .free / .set_config to work with pinctrl driver
> - register range with pinctrl driver

Nice, but...

> +       ret = gpiochip_add_pin_range(&madera_gpio->gpio_chip, "madera-pinctrl",
> +                                    0, 0, madera_gpio->gpio_chip.ngpio);
> +       if (ret) {
> +               dev_warn(&pdev->dev, "Failed to add pin range (%d)\n", ret);
> +               return ret;
> +       }

This is all fine, but we have generic code for adding ranges from
the device tree, see
Documentation/devicetree/bindings/gpio/gpio.txt

With that this range should not even be needed.
Apart from that it looks pretty solid.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [RFC 3/3] soc: qcom: rfsa driver
From: Sricharan R @ 2017-04-25 13:21 UTC (permalink / raw)
  To: Bjorn Andersson, Andy Gross, David Brown, Frank Rowand,
	Rob Herring, Mark Rutland
  Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170422173519.5782-3-bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

Hi Bjorn,

On 4/22/2017 11:05 PM, Bjorn Andersson wrote:
> The rfsa driver is used for allocating and exposing regions of shared
> memory with remote processors for the purpose of exchanging sector-data
> between the remote filesystem service and its clients.
> 
> It provides accessors for the properties needed by the user space remote
> filesystem implementation through sysfs and a character device that can be used
> to read and write the requested chunks of data.
> 

couple of minor nits.

> Signed-off-by: Bjorn Andersson <bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  drivers/soc/qcom/Kconfig  |   8 ++
>  drivers/soc/qcom/Makefile |   1 +
>  drivers/soc/qcom/rfsa.c   | 261 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 270 insertions(+)
>  create mode 100644 drivers/soc/qcom/rfsa.c
> 
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 9fca977ef18d..788a63cd430e 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -24,6 +24,14 @@ config QCOM_PM
>  	  modes. It interface with various system drivers to put the cores in
>  	  low power modes.
>  
> +config QCOM_RFSA
> +	tristate "Qualcomm Remote Filesystem Access driver"

 depends on ARCH_QCOM ?

> +	help
> +	  The Qualcomm remote filesystem access driver is used for allocating
> +	  and exposing regions of shared memory with remote processors for the
> +	  purpose of exchanging sector-data between the remote filesystem
> +	  service and its clients.
> +
>  config QCOM_SMEM
>  	tristate "Qualcomm Shared Memory Manager (SMEM)"
>  	depends on ARCH_QCOM
> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> index 414f0de274fa..d1bbc791ddc0 100644
> --- a/drivers/soc/qcom/Makefile
> +++ b/drivers/soc/qcom/Makefile
> @@ -1,6 +1,7 @@
>  obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
>  obj-$(CONFIG_QCOM_MDT_LOADER)	+= mdt_loader.o
>  obj-$(CONFIG_QCOM_PM)	+=	spm.o
> +obj-$(CONFIG_QCOM_RFSA)	+=	rfsa.o
>  obj-$(CONFIG_QCOM_SMD_RPM)	+= smd-rpm.o
>  obj-$(CONFIG_QCOM_SMEM) +=	smem.o
>  obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
> diff --git a/drivers/soc/qcom/rfsa.c b/drivers/soc/qcom/rfsa.c
> new file mode 100644
> index 000000000000..1b79976dad9d
> --- /dev/null
> +++ b/drivers/soc/qcom/rfsa.c
> @@ -0,0 +1,261 @@
> +/*
> + * Copyright (c) 2017 Linaro Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/cdev.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/of_fdt.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>
> +
> +#define QCOM_RFSA_DEV_MAX	(MINORMASK + 1)
> +
> +static dev_t qcom_rfsa_major;
> +
> +struct qcom_rfsa {
> +	struct device dev;
> +	struct cdev cdev;
> +
> +	void *base;
> +	phys_addr_t addr;
> +	phys_addr_t size;
> +
> +	unsigned int client_id;
> +};
> +
> +static ssize_t qcom_rfsa_show(struct device *dev,
> +			      struct device_attribute *attr,
> +			      char *buf);
> +
> +static DEVICE_ATTR(phys_addr, 0400, qcom_rfsa_show, NULL);
> +static DEVICE_ATTR(size, 0400, qcom_rfsa_show, NULL);
> +static DEVICE_ATTR(client_id, 0400, qcom_rfsa_show, NULL);
> +
> +static ssize_t qcom_rfsa_show(struct device *dev,
> +			      struct device_attribute *attr,
> +			      char *buf)
> +{
> +	struct qcom_rfsa *rfsa = container_of(dev, struct qcom_rfsa, dev);
> +
> +	if (attr == &dev_attr_phys_addr)
> +		return sprintf(buf, "%pa\n", &rfsa->addr);
> +	if (attr == &dev_attr_size)
> +		return sprintf(buf, "%pa\n", &rfsa->size);
> +	if (attr == &dev_attr_client_id)
> +		return sprintf(buf, "%d\n", rfsa->client_id);
> +
> +	return -EINVAL;
> +}
> +
> +static struct attribute *qcom_rfsa_attrs[] = {
> +	&dev_attr_phys_addr.attr,
> +	&dev_attr_size.attr,
> +	&dev_attr_client_id.attr,
> +	NULL
> +};
> +ATTRIBUTE_GROUPS(qcom_rfsa);
> +
> +static int qcom_rfsa_open(struct inode *inode, struct file *filp)
> +{
> +	struct qcom_rfsa *rfsa = container_of(inode->i_cdev, struct qcom_rfsa, cdev);
> +
> +	get_device(&rfsa->dev);
> +	filp->private_data = rfsa;
> +
> +	return 0;
> +}
> +static ssize_t qcom_rfsa_read(struct file *filp,
> +			      char __user *buf, size_t count, loff_t *f_pos)
> +{
> +	struct qcom_rfsa *rfsa = filp->private_data;
> +
> +	if (*f_pos >= rfsa->size)
> +		return 0;
> +
> +	if (*f_pos + count >= rfsa->size)
> +		count = rfsa->size - *f_pos;
> +
> +	if (copy_to_user(buf, rfsa->base + *f_pos, count))
> +		return -EFAULT;
> +
> +	*f_pos += count;
> +	return count;
> +}
> +
> +static ssize_t qcom_rfsa_write(struct file *filp,
> +			       const char __user *buf, size_t count,
> +			       loff_t *f_pos)
> +{
> +	struct qcom_rfsa *rfsa = filp->private_data;
> +
> +	if (*f_pos >= rfsa->size)
> +		return 0;
> +
> +	if (*f_pos + count >= rfsa->size)
> +		count = rfsa->size - *f_pos;
> +
> +	if (copy_from_user(rfsa->base + *f_pos, buf, count))
> +		return -EFAULT;
> +
> +	*f_pos += count;
> +	return count;
> +}
> +
> +static int qcom_rfsa_release(struct inode *inode, struct file *filp)
> +{
> +	struct qcom_rfsa *rfsa = filp->private_data;
> +
> +	put_device(&rfsa->dev);
> +
> +	return 0;
> +}
> +
> +static const struct file_operations qcom_rfsa_fops = {
> +	.owner = THIS_MODULE,
> +	.open = qcom_rfsa_open,
> +	.read = qcom_rfsa_read,
> +	.write = qcom_rfsa_write,
> +	.release = qcom_rfsa_release,
> +	.llseek = default_llseek,
> +};
> +
> +static void qcom_rfsa_release_device(struct device *dev)
> +{
> +	struct qcom_rfsa *rfsa = container_of(dev, struct qcom_rfsa, dev);
> +
> +	kfree(rfsa);
> +}
> +
> +static int qcom_rfsa_probe(struct platform_device *pdev)
> +{
> +	struct device_node *node = pdev->dev.of_node;
> +	struct reserved_mem *rmem;
> +	struct qcom_rfsa *rfsa;
> +	u32 client_id;
> +	int ret;
> +
> +	rmem = of_get_reserved_mem_by_idx(node, 0);
> +	if (!rmem) {
> +		dev_err(&pdev->dev, "failed to acquire memory region\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = of_property_read_u32(node, "qcom,client-id", &client_id);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to parse \"qcom,client-id\"\n");
> +		return ret;
> +
> +	}
> +
> +	rfsa = kzalloc(sizeof(*rfsa), GFP_KERNEL);
> +	if (!rfsa)
> +		return -ENOMEM;
> +
> +	rfsa->addr = rmem->base;
> +	rfsa->client_id = client_id;
> +	rfsa->size = rmem->size;
> +
> +	device_initialize(&rfsa->dev);
> +	rfsa->dev.parent = &pdev->dev;
> +	rfsa->dev.groups = qcom_rfsa_groups;
> +
> +	cdev_init(&rfsa->cdev, &qcom_rfsa_fops);
> +	rfsa->cdev.owner = THIS_MODULE;
> +
> +	dev_set_name(&rfsa->dev, "qcom_rfsa%d", client_id);
> +	rfsa->dev.id = client_id;
> +	rfsa->dev.devt = MKDEV(MAJOR(qcom_rfsa_major), client_id);
> +
> +	ret = cdev_device_add(&rfsa->cdev, &rfsa->dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to add cdev: %d\n", ret);
> +		put_device(&rfsa->dev);
> +		return ret;
> +	}
> +
> +	rfsa->dev.release = qcom_rfsa_release_device;
> +
> +	rfsa->base = devm_memremap(&rfsa->dev, rfsa->addr, rfsa->size, MEMREMAP_WC);
> +	if (IS_ERR(rfsa->base)) {
> +		dev_err(&pdev->dev, "failed to remap rfsa region\n");
> +
> +		device_del(&rfsa->dev);
> +		put_device(&rfsa->dev);
> +
> +		return PTR_ERR(rfsa->base);
> +	}
> +
> +	dev_set_drvdata(&pdev->dev, rfsa);
> +
> +	return 0;
> +}
> +
> +static int qcom_rfsa_remove(struct platform_device *pdev)
> +{
> +	struct qcom_rfsa *rfsa = dev_get_drvdata(&pdev->dev);
> +
> +	cdev_del(&rfsa->cdev);
> +	device_del(&rfsa->dev);

cdev_device_del instead of the above two ?

Regards,
 Sricharan


-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox