Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2 2/2] phy: meson: add USB2 PHY support for Meson GXL and GXM
From: Martin Blumenstingl @ 2017-03-28 21:33 UTC (permalink / raw)
  To: kishon-l0cyMroinI0,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	hendrik-MJglGmTD+GWCT0AhDRffsw, Martin Blumenstingl,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, carlo-KA+7E9HrN00dnm+yROfE0A,
	khilman-rdvid1DuHRBWk0Htik3J/w
In-Reply-To: <20170318130013.20771-3-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>

Hi Kishon,

On Sat, Mar 18, 2017 at 2:00 PM, Martin Blumenstingl
<martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:
> This adds a new driver for the USB2 PHYs found on Meson GXL and GXM SoCs
> (both SoCs are using the same USB PHY register layout).
>
> The USB2 PHY is a simple PHY which only has a few registers to configure
> the mode (host/device) and a reset register (to enable/disable the PHY).
>
> Unfortunately there are no datasheets available for this PHY. The driver
> was written by reading the code from Amlogic's GPL kernel sources and
> by analyzing the registers on an actual GXL and GXM device running the
> kernel that was shipped on the boards I have.
gentle ping - did you have time to review this patch in v2 yet?

> Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
> ---
>  drivers/phy/Kconfig              |  14 ++
>  drivers/phy/Makefile             |   1 +
>  drivers/phy/phy-meson-gxl-usb2.c | 273 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 288 insertions(+)
>  create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index dc5277ad1b5a..2573e139fd17 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -510,6 +510,19 @@ config PHY_MESON8B_USB2
>           and GXBB SoCs.
>           If unsure, say N.
>
> +config PHY_MESON_GXL_USB
> +       tristate "Meson GXL and GXM USB2 PHY drivers"
> +       default ARCH_MESON
> +       depends on OF && (ARCH_MESON || COMPILE_TEST)
> +       depends on USB_SUPPORT
> +       select USB_COMMON
> +       select GENERIC_PHY
> +       select REGMAP_MMIO
> +       help
> +         Enable this to support the Meson USB2 PHYs found in Meson
> +         GXL and GXM SoCs.
> +         If unsure, say N.
> +
>  config PHY_NSP_USB3
>         tristate "Broadcom NorthStar plus USB3 PHY driver"
>         depends on OF && (ARCH_BCM_NSP || COMPILE_TEST)
> @@ -518,4 +531,5 @@ config PHY_NSP_USB3
>         help
>           Enable this to support the Broadcom Northstar plus USB3 PHY.
>           If unsure, say N.
> +
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index e7b0feb1e125..e680b856e38e 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -62,4 +62,5 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE)         += phy-bcm-cygnus-pcie.o
>  obj-$(CONFIG_ARCH_TEGRA) += tegra/
>  obj-$(CONFIG_PHY_NS2_PCIE)             += phy-bcm-ns2-pcie.o
>  obj-$(CONFIG_PHY_MESON8B_USB2)         += phy-meson8b-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB)                += phy-meson-gxl-usb2.o
>  obj-$(CONFIG_PHY_NSP_USB3)             += phy-bcm-nsp-usb3.o
> diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
> new file mode 100644
> index 000000000000..4bf646a52c45
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb2.c
> @@ -0,0 +1,273 @@
> +/*
> + * Meson GXL and GXM USB2 PHY driver
> + *
> + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@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 version 2 as
> + * published by the Free Software Foundation.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +
> +/* bits [31:27] are read-only */
> +#define U2P_R0                                                 0x0
> +       #define U2P_R0_BYPASS_SEL                               BIT(0)
> +       #define U2P_R0_BYPASS_DM_EN                             BIT(1)
> +       #define U2P_R0_BYPASS_DP_EN                             BIT(2)
> +       #define U2P_R0_TXBITSTUFF_ENH                           BIT(3)
> +       #define U2P_R0_TXBITSTUFF_EN                            BIT(4)
> +       #define U2P_R0_DM_PULLDOWN                              BIT(5)
> +       #define U2P_R0_DP_PULLDOWN                              BIT(6)
> +       #define U2P_R0_DP_VBUS_VLD_EXT_SEL                      BIT(7)
> +       #define U2P_R0_DP_VBUS_VLD_EXT                          BIT(8)
> +       #define U2P_R0_ADP_PRB_EN                               BIT(9)
> +       #define U2P_R0_ADP_DISCHARGE                            BIT(10)
> +       #define U2P_R0_ADP_CHARGE                               BIT(11)
> +       #define U2P_R0_DRV_VBUS                                 BIT(12)
> +       #define U2P_R0_ID_PULLUP                                BIT(13)
> +       #define U2P_R0_LOOPBACK_EN_B                            BIT(14)
> +       #define U2P_R0_OTG_DISABLE                              BIT(15)
> +       #define U2P_R0_COMMON_ONN                               BIT(16)
> +       #define U2P_R0_FSEL_MASK                                GENMASK(19, 17)
> +       #define U2P_R0_REF_CLK_SEL_MASK                         GENMASK(21, 20)
> +       #define U2P_R0_POWER_ON_RESET                           BIT(22)
> +       #define U2P_R0_V_ATE_TEST_EN_B_MASK                     GENMASK(24, 23)
> +       #define U2P_R0_ID_SET_ID_DQ                             BIT(25)
> +       #define U2P_R0_ATE_RESET                                BIT(26)
> +       #define U2P_R0_FSV_MINUS                                BIT(27)
> +       #define U2P_R0_FSV_PLUS                                 BIT(28)
> +       #define U2P_R0_BYPASS_DM_DATA                           BIT(29)
> +       #define U2P_R0_BYPASS_DP_DATA                           BIT(30)
> +
> +#define U2P_R1                                                 0x4
> +       #define U2P_R1_BURN_IN_TEST                             BIT(0)
> +       #define U2P_R1_ACA_ENABLE                               BIT(1)
> +       #define U2P_R1_DCD_ENABLE                               BIT(2)
> +       #define U2P_R1_VDAT_SRC_EN_B                            BIT(3)
> +       #define U2P_R1_VDAT_DET_EN_B                            BIT(4)
> +       #define U2P_R1_CHARGES_SEL                              BIT(5)
> +       #define U2P_R1_TX_PREEMP_PULSE_TUNE                     BIT(6)
> +       #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK                  GENMASK(8, 7)
> +       #define U2P_R1_TX_RES_TUNE_MASK                         GENMASK(10, 9)
> +       #define U2P_R1_TX_RISE_TUNE_MASK                        GENMASK(12, 11)
> +       #define U2P_R1_TX_VREF_TUNE_MASK                        GENMASK(16, 13)
> +       #define U2P_R1_TX_FSLS_TUNE_MASK                        GENMASK(20, 17)
> +       #define U2P_R1_TX_HSXV_TUNE_MASK                        GENMASK(22, 21)
> +       #define U2P_R1_OTG_TUNE_MASK                            GENMASK(25, 23)
> +       #define U2P_R1_SQRX_TUNE_MASK                           GENMASK(28, 26)
> +       #define U2P_R1_COMP_DIS_TUNE_MASK                       GENMASK(31, 29)
> +
> +/* bits [31:14] are read-only */
> +#define U2P_R2                                                 0x8
> +       #define U2P_R2_DATA_IN_MASK                             GENMASK(3, 0)
> +       #define U2P_R2_DATA_IN_EN_MASK                          GENMASK(7, 4)
> +       #define U2P_R2_ADDR_MASK                                GENMASK(11, 8)
> +       #define U2P_R2_DATA_OUT_SEL                             BIT(12)
> +       #define U2P_R2_CLK                                      BIT(13)
> +       #define U2P_R2_DATA_OUT_MASK                            GENMASK(17, 14)
> +       #define U2P_R2_ACA_PIN_RANGE_C                          BIT(18)
> +       #define U2P_R2_ACA_PIN_RANGE_B                          BIT(19)
> +       #define U2P_R2_ACA_PIN_RANGE_A                          BIT(20)
> +       #define U2P_R2_ACA_PIN_GND                              BIT(21)
> +       #define U2P_R2_ACA_PIN_FLOAT                            BIT(22)
> +       #define U2P_R2_CHARGE_DETECT                            BIT(23)
> +       #define U2P_R2_DEVICE_SESSION_VALID                     BIT(24)
> +       #define U2P_R2_ADP_PROBE                                BIT(25)
> +       #define U2P_R2_ADP_SENSE                                BIT(26)
> +       #define U2P_R2_SESSION_END                              BIT(27)
> +       #define U2P_R2_VBUS_VALID                               BIT(28)
> +       #define U2P_R2_B_VALID                                  BIT(29)
> +       #define U2P_R2_A_VALID                                  BIT(30)
> +       #define U2P_R2_ID_DIG                                   BIT(31)
> +
> +#define U2P_R3                                                 0xc
> +
> +#define RESET_COMPLETE_TIME                            500
> +
> +struct phy_meson_gxl_usb2_priv {
> +       struct regmap           *regmap;
> +       enum phy_mode           mode;
> +       int                     is_enabled;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
> +       .reg_bits = 8,
> +       .val_bits = 32,
> +       .reg_stride = 4,
> +       .max_register = U2P_R3,
> +};
> +
> +static int phy_meson_gxl_usb2_reset(struct phy *phy)
> +{
> +       struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> +       if (priv->is_enabled) {
> +               /* reset the PHY and wait until settings are stabilized */
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> +                               U2P_R0_POWER_ON_RESET);
> +               udelay(RESET_COMPLETE_TIME);
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> +                                  0);
> +               udelay(RESET_COMPLETE_TIME);
> +       }
> +
> +       return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode)
> +{
> +       struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> +       switch (mode) {
> +       case PHY_MODE_USB_HOST:
> +       case PHY_MODE_USB_OTG:
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> +                                  U2P_R0_DM_PULLDOWN);
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> +                                  U2P_R0_DP_PULLDOWN);
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0);
> +               break;
> +
> +       case PHY_MODE_USB_DEVICE:
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> +                                  0);
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> +                                  0);
> +               regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP,
> +                                  U2P_R0_ID_PULLUP);
> +               break;
> +
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       phy_meson_gxl_usb2_reset(phy);
> +
> +       priv->mode = mode;
> +
> +       return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_off(struct phy *phy)
> +{
> +       struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> +       priv->is_enabled = 0;
> +
> +       /* power off the PHY by putting it into reset mode */
> +       regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> +                          U2P_R0_POWER_ON_RESET);
> +
> +       return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_on(struct phy *phy)
> +{
> +       struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +       int ret;
> +
> +       priv->is_enabled = 1;
> +
> +       /* power on the PHY by taking it out of reset mode */
> +       regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> +
> +       ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode);
> +       if (ret) {
> +               phy_meson_gxl_usb2_power_off(phy);
> +
> +               dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n",
> +                       priv->mode);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb2_ops = {
> +       .power_on       = phy_meson_gxl_usb2_power_on,
> +       .power_off      = phy_meson_gxl_usb2_power_off,
> +       .set_mode       = phy_meson_gxl_usb2_set_mode,
> +       .reset          = phy_meson_gxl_usb2_reset,
> +       .owner          = THIS_MODULE,
> +};
> +
> +static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct phy_provider *phy_provider;
> +       struct resource *res;
> +       struct phy_meson_gxl_usb2_priv *priv;
> +       struct phy *phy;
> +       void __iomem *base;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       platform_set_drvdata(pdev, priv);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       base = devm_ioremap_resource(dev, res);
> +       if (IS_ERR(base))
> +               return PTR_ERR(base);
> +
> +       switch (of_usb_get_dr_mode_by_phy(dev->of_node, -1)) {
> +       case USB_DR_MODE_PERIPHERAL:
> +               priv->mode = PHY_MODE_USB_DEVICE;
> +               break;
> +       case USB_DR_MODE_OTG:
> +               priv->mode = PHY_MODE_USB_OTG;
> +               break;
> +       case USB_DR_MODE_HOST:
> +       default:
> +               priv->mode = PHY_MODE_USB_HOST;
> +               break;
> +       }
> +
> +       priv->regmap = devm_regmap_init_mmio(dev, base,
> +                                            &phy_meson_gxl_usb2_regmap_conf);
> +       if (IS_ERR(priv->regmap))
> +               return PTR_ERR(priv->regmap);
> +
> +       phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
> +       if (IS_ERR(phy)) {
> +               dev_err(dev, "failed to create PHY\n");
> +               return PTR_ERR(phy);
> +       }
> +
> +       phy_set_drvdata(phy, priv);
> +
> +       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +
> +       return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id phy_meson_gxl_usb2_of_match[] = {
> +       { .compatible = "amlogic,meson-gxl-usb2-phy", },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match);
> +
> +static struct platform_driver phy_meson_gxl_usb2_driver = {
> +       .probe  = phy_meson_gxl_usb2_probe,
> +       .driver = {
> +               .name           = "phy-meson-gxl-usb2",
> +               .of_match_table = phy_meson_gxl_usb2_of_match,
> +       },
> +};
> +module_platform_driver(phy_meson_gxl_usb2_driver);
> +
> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>");
> +MODULE_DESCRIPTION("Meson GXL and GXM USB2 PHY driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.12.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

* [PATCH v2 0/8] bus: brcmstb_gisb: add support for GISBv7 arbiter
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland-5wv7dgnIgG8
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, catalin.marinas-5wv7dgnIgG8,
	will.deacon-5wv7dgnIgG8, computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	gregory.0xf0-Re5JQEeQqe8AvxtiuMwx3w,
	f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
	opendmb-Re5JQEeQqe8AvxtiuMwx3w,
	wangkefeng.wang-hv44wF8Li93QT0dZR+AlfA, james.morse-5wv7dgnIgG8,
	mingo-DgEjT+Ai2ygdnm+yROfE0A,
	sandeepa.s.prabhu-Re5JQEeQqe8AvxtiuMwx3w,
	shijie.huang-5wv7dgnIgG8, linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	treding-DDmLM1+adcrQT0dZR+AlfA, jonathanh-DDmLM1+adcrQT0dZR+AlfA,
	olof-nZhT3qVonbNeoWH0uzbU5w, mirza.krak-Re5JQEeQqe8AvxtiuMwx3w,
	suzuki.poulose-5wv7dgnIgG8, bgolaszewski-rdvid1DuHRBWk0Htik3J/w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

This patch set contains changes to enable the GISB arbiter driver
on the latest ARM64 architecture Set-Top Box chips from Broadcom.

This driver relies on being able to hook the abort handlers of
the processor core that are triggered by bus error signals
generated by the GISB bus arbiter hardware found in BCM7XXX chips.
The first two patches are based on the arm64/for-next/core
branch to enable this functionality for the arm64 architecture.

The remaining patches correct some issues with the existing driver,
add the ARM64 architecture specific support to the driver, and
finally add the new register map for the GISBv7 hardware first
appearing in the BCM7278 device.

Changes since v1 at [1]:
 - Removed code associated with hooking SError handling in favor
   of a registered notifier (Thanks Mark!)
 - Removed an unnecessary explicit cast (Thanks Gregory!)

[1] https://lkml.org/lkml/2017/3/24/413

Doug Berger (6):
  arm64: mm: mark fault_info __ro_after_init
  bus: brcmstb_gisb: Use register offsets with writes too
  bus: brcmstb_gisb: Correct hooking of ARM aborts
  bus: brcmstb_gisb: correct support for 64-bit address output
  bus: brcmstb_gisb: add notifier handling
  bus: brcmstb_gisb: update to support new revision

Florian Fainelli (2):
  arm64: mm: Allow installation of memory abort handlers
  bus: brcmstb_gisb: Add ARM64 support

 .../devicetree/bindings/bus/brcm,gisb-arb.txt      |   3 +-
 arch/arm64/include/asm/system_misc.h               |   3 +
 arch/arm64/mm/fault.c                              |  17 +++-
 drivers/bus/Kconfig                                |   2 +-
 drivers/bus/brcmstb_gisb.c                         | 111 ++++++++++++++++-----
 5 files changed, 106 insertions(+), 30 deletions(-)

-- 
2.12.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

* [PATCH v2 1/8] arm64: mm: Allow installation of memory abort handlers
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland
  Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
	gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
	wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
	shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
	suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>

From: Florian Fainelli <f.fainelli@gmail.com>

Similarly to what the ARM/Linux kernel provides, add a hook_fault_code()
function which allows drivers or other parts of the kernel to install
custom memory abort handlers. This is useful when a given SoC's busing
does not propagate the exact faulting physical address, but there is a
way to read it through e.g: a special arbiter driver.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm64/include/asm/system_misc.h |  3 +++
 arch/arm64/mm/fault.c                | 15 ++++++++++++++-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index bc812435bc76..e05f5b8c7c1c 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -38,6 +38,9 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
 void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
 					     struct pt_regs *),
 			   int sig, int code, const char *name);
+void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
+				       struct pt_regs *),
+		     int sig, int code, const char *name);
 
 struct mm_struct;
 extern void show_pte(struct mm_struct *mm, unsigned long addr);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 4bf899fb451b..cdf1260f1005 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -488,7 +488,7 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 	return 1;
 }
 
-static const struct fault_info {
+static struct fault_info {
 	int	(*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs);
 	int	sig;
 	int	code;
@@ -560,6 +560,19 @@ static const struct fault_info {
 	{ do_bad,		SIGBUS,  0,		"unknown 63"			},
 };
 
+void __init hook_fault_code(int nr,
+			    int (*fn)(unsigned long, unsigned int, struct pt_regs *),
+			    int sig, int code, const char *name)
+{
+	BUG_ON(nr < 0 || nr >= ARRAY_SIZE(fault_info));
+
+	fault_info[nr].fn	= fn;
+	fault_info[nr].sig	= sig;
+	fault_info[nr].code	= code;
+	fault_info[nr].name	= name;
+}
+
+
 static const char *fault_name(unsigned int esr)
 {
 	const struct fault_info *inf = fault_info + (esr & 63);
-- 
2.12.0

^ permalink raw reply related

* [PATCH v2 2/8] arm64: mm: mark fault_info __ro_after_init
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland
  Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
	gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
	wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
	shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
	suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>

The fault_info table must be made writeable to allow installation
of custom memory abort handlers, but it can be made read-only
after initialization to provide some protection.

Signed-off-by: Doug Berger <opendmb@gmail.com>
---
 arch/arm64/mm/fault.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index cdf1260f1005..43319ed58a47 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -493,7 +493,7 @@ static struct fault_info {
 	int	sig;
 	int	code;
 	const char *name;
-} fault_info[] = {
+} fault_info[] __ro_after_init = {
 	{ do_bad,		SIGBUS,  0,		"ttbr address size fault"	},
 	{ do_bad,		SIGBUS,  0,		"level 1 address size fault"	},
 	{ do_bad,		SIGBUS,  0,		"level 2 address size fault"	},
-- 
2.12.0

^ permalink raw reply related

* [PATCH v2 3/8] bus: brcmstb_gisb: Use register offsets with writes too
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland
  Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
	gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
	wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
	shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
	suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>

This commit corrects the bug introduced in commit f80835875d3d
("bus: brcmstb_gisb: Look up register offsets in a table") such
that gisb_write() translates the register enumeration into an
offset from the base address for writes as well as reads.

Fixes: f80835875d3d ("bus: brcmstb_gisb: Look up register offsets in a table")
Signed-off-by: Doug Berger <opendmb@gmail.com>
Acked-by: Gregory Fong <gregory.0xf0@gmail.com>
---
 drivers/bus/brcmstb_gisb.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 72fe0a5a8bf3..a94598d0945a 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Broadcom Corporation
+ * Copyright (C) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -127,9 +127,9 @@ static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
 		return;
 
 	if (gdev->big_endian)
-		iowrite32be(val, gdev->base + reg);
+		iowrite32be(val, gdev->base + offset);
 	else
-		iowrite32(val, gdev->base + reg);
+		iowrite32(val, gdev->base + offset);
 }
 
 static ssize_t gisb_arb_get_timeout(struct device *dev,
-- 
2.12.0

^ permalink raw reply related

* [PATCH v2 4/8] bus: brcmstb_gisb: Correct hooking of ARM aborts
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland-5wv7dgnIgG8
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, catalin.marinas-5wv7dgnIgG8,
	will.deacon-5wv7dgnIgG8, computersforpeace-Re5JQEeQqe8AvxtiuMwx3w,
	gregory.0xf0-Re5JQEeQqe8AvxtiuMwx3w,
	f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
	opendmb-Re5JQEeQqe8AvxtiuMwx3w,
	wangkefeng.wang-hv44wF8Li93QT0dZR+AlfA, james.morse-5wv7dgnIgG8,
	mingo-DgEjT+Ai2ygdnm+yROfE0A,
	sandeepa.s.prabhu-Re5JQEeQqe8AvxtiuMwx3w,
	shijie.huang-5wv7dgnIgG8, linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	treding-DDmLM1+adcrQT0dZR+AlfA, jonathanh-DDmLM1+adcrQT0dZR+AlfA,
	olof-nZhT3qVonbNeoWH0uzbU5w, mirza.krak-Re5JQEeQqe8AvxtiuMwx3w,
	suzuki.poulose-5wv7dgnIgG8, bgolaszewski-rdvid1DuHRBWk0Htik3J/w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170328213431.10904-1-opendmb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

The fault status reporting in the FSR registers is different depending
on whether the Long Physical Address Extension (LPAE) is being used.

This commit corrects the registerring of fault handlers for arm
architecture kernels when the LPAE is enabled.  It also forces the
handler to report that the abort exception was unhandled so that the
appropriate signal is sent to the offending user process.

Signed-off-by: Doug Berger <opendmb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/bus/brcmstb_gisb.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index a94598d0945a..9eba0143f1a4 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -225,27 +225,29 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
 static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
 				     struct pt_regs *regs)
 {
-	int ret = 0;
 	struct brcmstb_gisb_arb_device *gdev;
 
 	/* iterate over each GISB arb registered handlers */
 	list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
-		ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error");
+		brcmstb_gisb_arb_decode_addr(gdev, "bus error");
+
+#if !defined(CONFIG_ARM_LPAE)
 	/*
 	 * If it was an imprecise abort, then we need to correct the
 	 * return address to be _after_ the instruction.
 	*/
 	if (fsr & (1 << 10))
 		regs->ARM_pc += 4;
+#endif
 
-	return ret;
+	/* Always report unhandled exception */
+	return 1;
 }
 #endif
 
 #ifdef CONFIG_MIPS
 static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
 {
-	int ret = 0;
 	struct brcmstb_gisb_arb_device *gdev;
 	u32 cap_status;
 
@@ -258,7 +260,7 @@ static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
 			goto out;
 		}
 
-		ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error");
+		brcmstb_gisb_arb_decode_addr(gdev, "bus error");
 	}
 out:
 	return is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
@@ -379,9 +381,16 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
 	list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list);
 
 #ifdef CONFIG_ARM
+#ifdef CONFIG_ARM_LPAE
+	hook_fault_code(16, brcmstb_bus_error_handler, SIGBUS, 0,
+			"synchronous external abort");
+	hook_fault_code(17, brcmstb_bus_error_handler, SIGBUS, 0,
+			"asynchronous external abort");
+#else
 	hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
 			"imprecise external abort");
 #endif
+#endif /* CONFIG_ARM */
 #ifdef CONFIG_MIPS
 	board_be_handler = brcmstb_bus_error_handler;
 #endif
-- 
2.12.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

* [PATCH v2 5/8] bus: brcmstb_gisb: correct support for 64-bit address output
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland
  Cc: wangkefeng.wang, catalin.marinas, linus.walleij, will.deacon,
	mingo, f.fainelli, jonathanh, bgolaszewski,
	bcm-kernel-feedback-list, shijie.huang, opendmb, treding,
	devicetree, suzuki.poulose, robh+dt, gregory.0xf0,
	sandeepa.s.prabhu, linux-arm-kernel, mirza.krak, linux-kernel,
	james.morse, olof, computersforpeace
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>

The GISB bus can support addresses beyond 32-bits.  So this commit
corrects support for reading a captured 64-bit address into a 64-bit
variable by obtaining the high bits from the ARB_ERR_CAP_HI_ADDR
register (when present) and then outputting the full 64-bit value.

It also removes unused definitions.

Fixes: 44127b771d9c ("bus: add Broadcom GISB bus arbiter timeout/error handler")
Signed-off-by: Doug Berger <opendmb@gmail.com>
Acked-by: Gregory Fong <gregory.0xf0@gmail.com>
---
 drivers/bus/brcmstb_gisb.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 9eba0143f1a4..edf79432f899 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -37,8 +37,6 @@
 #define  ARB_ERR_CAP_CLEAR		(1 << 0)
 #define  ARB_ERR_CAP_STATUS_TIMEOUT	(1 << 12)
 #define  ARB_ERR_CAP_STATUS_TEA		(1 << 11)
-#define  ARB_ERR_CAP_STATUS_BS_SHIFT	(1 << 2)
-#define  ARB_ERR_CAP_STATUS_BS_MASK	0x3c
 #define  ARB_ERR_CAP_STATUS_WRITE	(1 << 1)
 #define  ARB_ERR_CAP_STATUS_VALID	(1 << 0)
 
@@ -47,7 +45,6 @@ enum {
 	ARB_ERR_CAP_CLR,
 	ARB_ERR_CAP_HI_ADDR,
 	ARB_ERR_CAP_ADDR,
-	ARB_ERR_CAP_DATA,
 	ARB_ERR_CAP_STATUS,
 	ARB_ERR_CAP_MASTER,
 };
@@ -57,7 +54,6 @@ static const int gisb_offsets_bcm7038[] = {
 	[ARB_ERR_CAP_CLR]	= 0x0c4,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x0c8,
-	[ARB_ERR_CAP_DATA]	= 0x0cc,
 	[ARB_ERR_CAP_STATUS]	= 0x0d0,
 	[ARB_ERR_CAP_MASTER]	= -1,
 };
@@ -67,7 +63,6 @@ static const int gisb_offsets_bcm7400[] = {
 	[ARB_ERR_CAP_CLR]	= 0x0c8,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x0cc,
-	[ARB_ERR_CAP_DATA]	= 0x0d0,
 	[ARB_ERR_CAP_STATUS]	= 0x0d4,
 	[ARB_ERR_CAP_MASTER]	= 0x0d8,
 };
@@ -77,7 +72,6 @@ static const int gisb_offsets_bcm7435[] = {
 	[ARB_ERR_CAP_CLR]	= 0x168,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x16c,
-	[ARB_ERR_CAP_DATA]	= 0x170,
 	[ARB_ERR_CAP_STATUS]	= 0x174,
 	[ARB_ERR_CAP_MASTER]	= 0x178,
 };
@@ -87,7 +81,6 @@ static const int gisb_offsets_bcm7445[] = {
 	[ARB_ERR_CAP_CLR]	= 0x7e4,
 	[ARB_ERR_CAP_HI_ADDR]	= 0x7e8,
 	[ARB_ERR_CAP_ADDR]	= 0x7ec,
-	[ARB_ERR_CAP_DATA]	= 0x7f0,
 	[ARB_ERR_CAP_STATUS]	= 0x7f4,
 	[ARB_ERR_CAP_MASTER]	= 0x7f8,
 };
@@ -109,9 +102,13 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
 {
 	int offset = gdev->gisb_offsets[reg];
 
-	/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
-	if (offset == -1)
-		return 1;
+	if (offset < 0) {
+		/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
+		if (reg == ARB_ERR_CAP_MASTER)
+			return 1;
+		else
+			return 0;
+	}
 
 	if (gdev->big_endian)
 		return ioread32be(gdev->base + offset);
@@ -119,6 +116,16 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
 		return ioread32(gdev->base + offset);
 }
 
+static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
+{
+	u64 value;
+
+	value = gisb_read(gdev, ARB_ERR_CAP_ADDR);
+	value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
+
+	return value;
+}
+
 static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
 {
 	int offset = gdev->gisb_offsets[reg];
@@ -185,7 +192,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
 					const char *reason)
 {
 	u32 cap_status;
-	unsigned long arb_addr;
+	u64 arb_addr;
 	u32 master;
 	const char *m_name;
 	char m_fmt[11];
@@ -197,10 +204,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
 		return 1;
 
 	/* Read the address and master */
-	arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
-#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
-	arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
-#endif
+	arb_addr = gisb_read_address(gdev);
 	master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
 
 	m_name = brcmstb_gisb_master_to_str(gdev, master);
@@ -209,7 +213,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
 		m_name = m_fmt;
 	}
 
-	pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n",
+	pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
 		__func__, reason, arb_addr,
 		cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
 		cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
-- 
2.12.0

^ permalink raw reply related

* [PATCH v2 6/8] bus: brcmstb_gisb: Add ARM64 support
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland
  Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
	gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
	wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
	shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
	suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>

From: Florian Fainelli <f.fainelli@gmail.com>

Hook to the ARM64 data abort exception #16: synchronous external
abort, which is how the GISB errors will be funneled back to the
ARM64 CPU in case of problems

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/bus/Kconfig        |  2 +-
 drivers/bus/brcmstb_gisb.c | 15 ++++++++++++---
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 0a52da439abf..d2a5f1184022 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -57,7 +57,7 @@ config ARM_CCN
 
 config BRCMSTB_GISB_ARB
 	bool "Broadcom STB GISB bus arbiter"
-	depends on ARM || MIPS
+	depends on ARM || ARM64 || MIPS
 	default ARCH_BRCMSTB || BMIPS_GENERIC
 	help
 	  Driver for the Broadcom Set Top Box System-on-a-chip internal bus
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index edf79432f899..500b6bb5c739 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -30,6 +30,11 @@
 #include <asm/signal.h>
 #endif
 
+#ifdef CONFIG_ARM64
+#include <asm/signal.h>
+#include <asm/system_misc.h>
+#endif
+
 #ifdef CONFIG_MIPS
 #include <asm/traps.h>
 #endif
@@ -225,7 +230,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
 	return 0;
 }
 
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
 static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
 				     struct pt_regs *regs)
 {
@@ -235,7 +240,7 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
 	list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
 		brcmstb_gisb_arb_decode_addr(gdev, "bus error");
 
-#if !defined(CONFIG_ARM_LPAE)
+#if defined(CONFIG_ARM) && !defined(CONFIG_ARM_LPAE)
 	/*
 	 * If it was an imprecise abort, then we need to correct the
 	 * return address to be _after_ the instruction.
@@ -247,7 +252,7 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
 	/* Always report unhandled exception */
 	return 1;
 }
-#endif
+#endif /* CONFIG_ARM || CONFIG_ARM64 */
 
 #ifdef CONFIG_MIPS
 static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup)
@@ -395,6 +400,10 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
 			"imprecise external abort");
 #endif
 #endif /* CONFIG_ARM */
+#ifdef CONFIG_ARM64
+	hook_fault_code(16, brcmstb_bus_error_handler, SIGBUS, 0,
+			"synchronous external abort");
+#endif
 #ifdef CONFIG_MIPS
 	board_be_handler = brcmstb_bus_error_handler;
 #endif
-- 
2.12.0

^ permalink raw reply related

* [PATCH v2 7/8] bus: brcmstb_gisb: add notifier handling
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland
  Cc: wangkefeng.wang, catalin.marinas, linus.walleij, will.deacon,
	mingo, f.fainelli, jonathanh, bgolaszewski,
	bcm-kernel-feedback-list, shijie.huang, opendmb, treding,
	devicetree, suzuki.poulose, robh+dt, gregory.0xf0,
	sandeepa.s.prabhu, linux-arm-kernel, mirza.krak, linux-kernel,
	james.morse, olof, computersforpeace
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>

Check for GISB arbitration errors through a chained notifier
when a process dies or a kernel panic occurs.  This allows a
meaningful diagnostic message to occur along with other
diagnostic information.

Notably writes to a bad GISB address on an ARM64 architecture
kernel cause unrecoverable SError aborts and this allows the
cause of the abort to be seen.

Signed-off-by: Doug Berger <opendmb@gmail.com>
---
 drivers/bus/brcmstb_gisb.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 500b6bb5c739..774729002b8c 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -24,6 +24,8 @@
 #include <linux/of.h>
 #include <linux/bitops.h>
 #include <linux/pm.h>
+#include <linux/kernel.h>
+#include <linux/kdebug.h>
 
 #ifdef CONFIG_ARM
 #include <asm/bug.h>
@@ -290,6 +292,25 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/*
+ * Dump out gisb errors on die or panic.
+ */
+static int dump_gisb_error(struct notifier_block *self, unsigned long v,
+			   void *p)
+{
+	struct brcmstb_gisb_arb_device *gdev;
+
+	/* iterate over each GISB arb registered handlers */
+	list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next)
+		brcmstb_gisb_arb_decode_addr(gdev, "async abort");
+
+	return 0;
+}
+
+static struct notifier_block gisb_error_notifier = {
+	.notifier_call = dump_gisb_error,
+};
+
 static DEVICE_ATTR(gisb_arb_timeout, S_IWUSR | S_IRUGO,
 		gisb_arb_get_timeout, gisb_arb_set_timeout);
 
@@ -408,6 +429,12 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
 	board_be_handler = brcmstb_bus_error_handler;
 #endif
 
+	if (list_is_singular(&brcmstb_gisb_arb_device_list)) {
+		register_die_notifier(&gisb_error_notifier);
+		atomic_notifier_chain_register(&panic_notifier_list,
+					       &gisb_error_notifier);
+	}
+
 	dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
 			gdev->base, timeout_irq, tea_irq);
 
-- 
2.12.0

^ permalink raw reply related

* [PATCH v2 8/8] bus: brcmstb_gisb: update to support new revision
From: Doug Berger @ 2017-03-28 21:34 UTC (permalink / raw)
  To: mark.rutland
  Cc: robh+dt, catalin.marinas, will.deacon, computersforpeace,
	gregory.0xf0, f.fainelli, bcm-kernel-feedback-list, opendmb,
	wangkefeng.wang, james.morse, mingo, sandeepa.s.prabhu,
	shijie.huang, linus.walleij, treding, jonathanh, olof, mirza.krak,
	suzuki.poulose, bgolaszewski, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20170328213431.10904-1-opendmb@gmail.com>

The 7278 introduces a new version of this core.  This
commit adds support for that revision.

Signed-off-by: Doug Berger <opendmb@gmail.com>
---
 Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt |  3 ++-
 drivers/bus/brcmstb_gisb.c                              | 10 ++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
index 1eceefb20f01..8a6c3c2e58fe 100644
--- a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
+++ b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
@@ -3,7 +3,8 @@ Broadcom GISB bus Arbiter controller
 Required properties:
 
 - compatible:
-    "brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for 28nm chips
+    "brcm,bcm7278-gisb-arb" for V7 28nm chips
+    "brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for other 28nm chips
     "brcm,bcm7435-gisb-arb" for newer 40nm chips
     "brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips
     "brcm,bcm7038-gisb-arb" for 130nm chips
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 774729002b8c..6c3b0dda75f2 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -65,6 +65,15 @@ static const int gisb_offsets_bcm7038[] = {
 	[ARB_ERR_CAP_MASTER]	= -1,
 };
 
+static const int gisb_offsets_bcm7278[] = {
+	[ARB_TIMER]		= 0x008,
+	[ARB_ERR_CAP_CLR]	= 0x7f8,
+	[ARB_ERR_CAP_HI_ADDR]	= -1,
+	[ARB_ERR_CAP_ADDR]	= 0x7e0,
+	[ARB_ERR_CAP_STATUS]	= 0x7f0,
+	[ARB_ERR_CAP_MASTER]	= 0x7f4,
+};
+
 static const int gisb_offsets_bcm7400[] = {
 	[ARB_TIMER]		= 0x00c,
 	[ARB_ERR_CAP_CLR]	= 0x0c8,
@@ -328,6 +337,7 @@ static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
 	{ .compatible = "brcm,bcm7445-gisb-arb", .data = gisb_offsets_bcm7445 },
 	{ .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 },
 	{ .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 },
+	{ .compatible = "brcm,bcm7278-gisb-arb", .data = gisb_offsets_bcm7278 },
 	{ .compatible = "brcm,bcm7038-gisb-arb", .data = gisb_offsets_bcm7038 },
 	{ },
 };
-- 
2.12.0

^ permalink raw reply related

* [PATCH v5 1/2] Documentation: dt-bindings: Document bindings for Aspeed ADC
From: Rick Altherr @ 2017-03-28 21:52 UTC (permalink / raw)
  To: openbmc-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, Hartmut Knaack, Rob Herring,
	Lars-Peter Clausen, Mark Rutland, Jonathan Cameron,
	Peter Meerwald-Stadler

Signed-off-by: Rick Altherr <raltherr-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
---

Changes in v5: None
Changes in v4: None
Changes in v3:
- Consistently write hex contstants with lowercase letters
- Drop model numbers from description as same IP is used in every generation

Changes in v2:
- Rewritten as an IIO ADC device

 .../devicetree/bindings/iio/adc/aspeed_adc.txt       | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
new file mode 100644
index 000000000000..674e133b7cd7
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
@@ -0,0 +1,20 @@
+Aspeed ADC
+
+This device is a 10-bit converter for 16 voltage channels.  All inputs are
+single ended.
+
+Required properties:
+- compatible: Should be "aspeed,ast2400-adc" or "aspeed,ast2500-adc"
+- reg: memory window mapping address and length
+- clocks: Input clock used to derive the sample clock. Expected to be the
+          SoC's APB clock.
+- #io-channel-cells: Must be set to <1> to indicate channels are selected
+                     by index.
+
+Example:
+	adc@1e6e9000 {
+		compatible = "aspeed,ast2400-adc";
+		reg = <0x1e6e9000 0xb0>;
+		clocks = <&clk_apb>;
+		#io-channel-cells = <1>;
+	};
-- 
2.12.2.564.g063fe858b8-goog

--
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 v3 1/3] clk: meson-gxbb: expose clock CLKID_RNG0
From: Michael Turquette @ 2017-03-28 22:07 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Kevin Hilman, Heiner Kallweit, Jerome Brunet, Neil Armstrong,
	linux-amlogic, linux-crypto, Stephen Boyd, linux-clk, Linux-DT
In-Reply-To: <20170323075602.GA6054@gondor.apana.org.au>

Herbert,

On Thu, Mar 23, 2017 at 12:56 AM, Herbert Xu
<herbert@gondor.apana.org.au> wrote:
> On Wed, Mar 22, 2017 at 08:24:08AM -0700, Kevin Hilman wrote:
>>
>> Because this will be causing conflicts with both the platform (amlogic)
>> tree and the clk tree, could provide an immutable branch where these are
>> applied to help us handle these conflicts?
>
> If you apply the same patches to your tree there should be no
> conflicts at all.  git is able to resolve this automatically.

The commits will have different SHA1 hashes (commit id's). Having
multiple "copies" of the same patch with separate id's is undesirable
and completely avoidable. Immutable, shared branches resolve this
issue.

Best regards,
Mike

>
> Cheers,
> --
> Email: Herbert Xu <herbert@gondor.apana.org.au>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [RFC 3/8] cpufreq: imx6q: Set max suspend_freq to avoid changes during suspend
From: Rafael J. Wysocki @ 2017-03-28 22:23 UTC (permalink / raw)
  To: Leonard Crestez
  Cc: Viresh Kumar, Mark Brown, Liam Girdwood, Shawn Guo, Sascha Hauer,
	Robin Gong, Anson Huang, Irina Tirdea, Rob Herring, Mark Rutland,
	Fabio Estevam, Octavian Purdila, linux-pm, linux-arm-kernel,
	devicetree, linux-kernel
In-Reply-To: <45185440.SBt0mf6LXq@aspire.rjw.lan>

On Tuesday, March 28, 2017 10:50:50 PM Rafael J. Wysocki wrote:
> On Tuesday, March 28, 2017 11:03:51 PM Leonard Crestez wrote:
> > On Thu, 2017-03-23 at 10:04 +0530, Viresh Kumar wrote:
> > > On 22-03-17, 18:53, Leonard Crestez wrote:
> > > > If the cpufreq driver tries to modify voltage/freq during suspend/resume
> > > > it might need to control an external PMIC via I2C or SPI but those
> > > > devices might be already suspended.
> > > > 
> > > > To avoid this scenario we just increase cpufreq to highest setpoint
> > > > before suspend. This issue can easily be triggered by ldo-bypass but in
> > > > theory any regulator set_voltage call can end up having to modify
> > > > external supply voltages.
> > > > 
> > > > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> > > > ---
> > > >  drivers/cpufreq/imx6q-cpufreq.c | 2 ++
> > > >  1 file changed, 2 insertions(+)
> > > 
> > > Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
> > 
> > The first couple of patches are obvious fixes despite being marked as
> > RFC. It would be great if you could apply them to your tree separately
> 
> Why?
> 
> > from the rest of the series but I'm not sure what the process is here.
> 
> Well, you have to talk to me.

OK, so if I understand this correctly, you would like the patches ACKed by
Viresh to be applied regardless of what happens to the rest of the series,
right?

In that case please resend them separately without the [RFC] tag and with
the ACKs from Viresh.

Thanks,
Rafael

^ permalink raw reply

* Re: [PATCH 1/1] of: Move OF property and graph API from base.c to property.c
From: Frank Rowand @ 2017-03-28 23:51 UTC (permalink / raw)
  To: Sakari Ailus, linux-acpi, devicetree, robh
  Cc: sudeep.holla, lorenzo.pieralisi, mika.westerberg, rafael,
	mark.rutland, broonie, ahs3
In-Reply-To: <1490353147-11917-1-git-send-email-sakari.ailus@linux.intel.com>

Hi Sakari,

On 03/24/17 03:59, Sakari Ailus wrote:
> base.c contains both core OF functions and increasingly other
> functionality such as accessing properties and graphs, including
> convenience functions. In the near future this would also include OF
> specific implementation of the fwnode property and graph APIs. Prepare for
> this by moving the functionality to property.c.

For future me, for when I look back and read this commit, please add something
to the effect of:

  Create driver/of/property.c to contain procedures for accessing and
  interpreting device tree properties.  The procedures are moved from
  drivers/of/base.c, with no changes other than copying only the
  includes required by the moved procedures.

> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
> Hi Rob,
> 
> Did you mean something like this?
> 
> Because of the upcoming changes to the base.c in linux-next I split the
> patchset reworking the implementation of the fwnode property interface and
> distributing it across the FW implementation. This patch is applicable to
> the for-next now, the rest in the set require the ACPI graph support
> patches as well.

One more comment below in the "diff --git a/drivers/of/property.c b/drivers/of/property.c"


> 
> I'll post them shortly.
> 
> Kind regards,
> Sakari
> 
>  drivers/of/Makefile   |   2 +-
>  drivers/of/base.c     | 702 ------------------------------------------------
>  drivers/of/property.c | 727 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 728 insertions(+), 703 deletions(-)
>  create mode 100644 drivers/of/property.c
> 
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index d7efd9d..97dc01c 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -1,4 +1,4 @@
> -obj-y = base.o device.o platform.o
> +obj-y = base.o device.o platform.o property.o
>  obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
>  obj-$(CONFIG_OF_FLATTREE) += fdt.o
>  obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index d7c4629..d57188d 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1113,427 +1113,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
>  }
>  EXPORT_SYMBOL(of_find_node_by_phandle);
>  
> -/**
> - * of_property_count_elems_of_size - Count the number of elements in a property
> - *
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @elem_size:	size of the individual element
> - *
> - * Search for a property in a device node and count the number of elements of
> - * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
> - * property does not exist or its length does not match a multiple of elem_size
> - * and -ENODATA if the property does not have a value.
> - */
> -int of_property_count_elems_of_size(const struct device_node *np,
> -				const char *propname, int elem_size)
> -{
> -	struct property *prop = of_find_property(np, propname, NULL);
> -
> -	if (!prop)
> -		return -EINVAL;
> -	if (!prop->value)
> -		return -ENODATA;
> -
> -	if (prop->length % elem_size != 0) {
> -		pr_err("size of %s in node %s is not a multiple of %d\n",
> -		       propname, np->full_name, elem_size);
> -		return -EINVAL;
> -	}
> -
> -	return prop->length / elem_size;
> -}
> -EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
> -
> -/**
> - * of_find_property_value_of_size
> - *
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @min:	minimum allowed length of property value
> - * @max:	maximum allowed length of property value (0 means unlimited)
> - * @len:	if !=NULL, actual length is written to here
> - *
> - * Search for a property in a device node and valid the requested size.
> - * Returns the property value on success, -EINVAL if the property does not
> - *  exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
> - * property data is too small or too large.
> - *
> - */
> -static void *of_find_property_value_of_size(const struct device_node *np,
> -			const char *propname, u32 min, u32 max, size_t *len)
> -{
> -	struct property *prop = of_find_property(np, propname, NULL);
> -
> -	if (!prop)
> -		return ERR_PTR(-EINVAL);
> -	if (!prop->value)
> -		return ERR_PTR(-ENODATA);
> -	if (prop->length < min)
> -		return ERR_PTR(-EOVERFLOW);
> -	if (max && prop->length > max)
> -		return ERR_PTR(-EOVERFLOW);
> -
> -	if (len)
> -		*len = prop->length;
> -
> -	return prop->value;
> -}
> -
> -/**
> - * of_property_read_u32_index - Find and read a u32 from a multi-value property.
> - *
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @index:	index of the u32 in the list of values
> - * @out_value:	pointer to return value, modified only if no error.
> - *
> - * Search for a property in a device node and read nth 32-bit value from
> - * it. Returns 0 on success, -EINVAL if the property does not exist,
> - * -ENODATA if property does not have a value, and -EOVERFLOW if the
> - * property data isn't large enough.
> - *
> - * The out_value is modified only if a valid u32 value can be decoded.
> - */
> -int of_property_read_u32_index(const struct device_node *np,
> -				       const char *propname,
> -				       u32 index, u32 *out_value)
> -{
> -	const u32 *val = of_find_property_value_of_size(np, propname,
> -					((index + 1) * sizeof(*out_value)),
> -					0,
> -					NULL);
> -
> -	if (IS_ERR(val))
> -		return PTR_ERR(val);
> -
> -	*out_value = be32_to_cpup(((__be32 *)val) + index);
> -	return 0;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_u32_index);
> -
> -/**
> - * of_property_read_variable_u8_array - Find and read an array of u8 from a
> - * property, with bounds on the minimum and maximum array size.
> - *
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @out_values:	pointer to return value, modified only if return value is 0.
> - * @sz_min:	minimum number of array elements to read
> - * @sz_max:	maximum number of array elements to read, if zero there is no
> - *		upper limit on the number of elements in the dts entry but only
> - *		sz_min will be read.
> - *
> - * Search for a property in a device node and read 8-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * dts entry of array should be like:
> - *	property = /bits/ 8 <0x50 0x60 0x70>;
> - *
> - * The out_values is modified only if a valid u8 value can be decoded.
> - */
> -int of_property_read_variable_u8_array(const struct device_node *np,
> -					const char *propname, u8 *out_values,
> -					size_t sz_min, size_t sz_max)
> -{
> -	size_t sz, count;
> -	const u8 *val = of_find_property_value_of_size(np, propname,
> -						(sz_min * sizeof(*out_values)),
> -						(sz_max * sizeof(*out_values)),
> -						&sz);
> -
> -	if (IS_ERR(val))
> -		return PTR_ERR(val);
> -
> -	if (!sz_max)
> -		sz = sz_min;
> -	else
> -		sz /= sizeof(*out_values);
> -
> -	count = sz;
> -	while (count--)
> -		*out_values++ = *val++;
> -
> -	return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
> -
> -/**
> - * of_property_read_variable_u16_array - Find and read an array of u16 from a
> - * property, with bounds on the minimum and maximum array size.
> - *
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @out_values:	pointer to return value, modified only if return value is 0.
> - * @sz_min:	minimum number of array elements to read
> - * @sz_max:	maximum number of array elements to read, if zero there is no
> - *		upper limit on the number of elements in the dts entry but only
> - *		sz_min will be read.
> - *
> - * Search for a property in a device node and read 16-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * dts entry of array should be like:
> - *	property = /bits/ 16 <0x5000 0x6000 0x7000>;
> - *
> - * The out_values is modified only if a valid u16 value can be decoded.
> - */
> -int of_property_read_variable_u16_array(const struct device_node *np,
> -					const char *propname, u16 *out_values,
> -					size_t sz_min, size_t sz_max)
> -{
> -	size_t sz, count;
> -	const __be16 *val = of_find_property_value_of_size(np, propname,
> -						(sz_min * sizeof(*out_values)),
> -						(sz_max * sizeof(*out_values)),
> -						&sz);
> -
> -	if (IS_ERR(val))
> -		return PTR_ERR(val);
> -
> -	if (!sz_max)
> -		sz = sz_min;
> -	else
> -		sz /= sizeof(*out_values);
> -
> -	count = sz;
> -	while (count--)
> -		*out_values++ = be16_to_cpup(val++);
> -
> -	return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
> -
> -/**
> - * of_property_read_variable_u32_array - Find and read an array of 32 bit
> - * integers from a property, with bounds on the minimum and maximum array size.
> - *
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @out_values:	pointer to return value, modified only if return value is 0.
> - * @sz_min:	minimum number of array elements to read
> - * @sz_max:	maximum number of array elements to read, if zero there is no
> - *		upper limit on the number of elements in the dts entry but only
> - *		sz_min will be read.
> - *
> - * Search for a property in a device node and read 32-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * The out_values is modified only if a valid u32 value can be decoded.
> - */
> -int of_property_read_variable_u32_array(const struct device_node *np,
> -			       const char *propname, u32 *out_values,
> -			       size_t sz_min, size_t sz_max)
> -{
> -	size_t sz, count;
> -	const __be32 *val = of_find_property_value_of_size(np, propname,
> -						(sz_min * sizeof(*out_values)),
> -						(sz_max * sizeof(*out_values)),
> -						&sz);
> -
> -	if (IS_ERR(val))
> -		return PTR_ERR(val);
> -
> -	if (!sz_max)
> -		sz = sz_min;
> -	else
> -		sz /= sizeof(*out_values);
> -
> -	count = sz;
> -	while (count--)
> -		*out_values++ = be32_to_cpup(val++);
> -
> -	return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
> -
> -/**
> - * of_property_read_u64 - Find and read a 64 bit integer from a property
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @out_value:	pointer to return value, modified only if return value is 0.
> - *
> - * Search for a property in a device node and read a 64-bit value from
> - * it. Returns 0 on success, -EINVAL if the property does not exist,
> - * -ENODATA if property does not have a value, and -EOVERFLOW if the
> - * property data isn't large enough.
> - *
> - * The out_value is modified only if a valid u64 value can be decoded.
> - */
> -int of_property_read_u64(const struct device_node *np, const char *propname,
> -			 u64 *out_value)
> -{
> -	const __be32 *val = of_find_property_value_of_size(np, propname,
> -						sizeof(*out_value),
> -						0,
> -						NULL);
> -
> -	if (IS_ERR(val))
> -		return PTR_ERR(val);
> -
> -	*out_value = of_read_number(val, 2);
> -	return 0;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_u64);
> -
> -/**
> - * of_property_read_variable_u64_array - Find and read an array of 64 bit
> - * integers from a property, with bounds on the minimum and maximum array size.
> - *
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @out_values:	pointer to return value, modified only if return value is 0.
> - * @sz_min:	minimum number of array elements to read
> - * @sz_max:	maximum number of array elements to read, if zero there is no
> - *		upper limit on the number of elements in the dts entry but only
> - *		sz_min will be read.
> - *
> - * Search for a property in a device node and read 64-bit value(s) from
> - * it. Returns number of elements read on success, -EINVAL if the property
> - * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> - * if the property data is smaller than sz_min or longer than sz_max.
> - *
> - * The out_values is modified only if a valid u64 value can be decoded.
> - */
> -int of_property_read_variable_u64_array(const struct device_node *np,
> -			       const char *propname, u64 *out_values,
> -			       size_t sz_min, size_t sz_max)
> -{
> -	size_t sz, count;
> -	const __be32 *val = of_find_property_value_of_size(np, propname,
> -						(sz_min * sizeof(*out_values)),
> -						(sz_max * sizeof(*out_values)),
> -						&sz);
> -
> -	if (IS_ERR(val))
> -		return PTR_ERR(val);
> -
> -	if (!sz_max)
> -		sz = sz_min;
> -	else
> -		sz /= sizeof(*out_values);
> -
> -	count = sz;
> -	while (count--) {
> -		*out_values++ = of_read_number(val, 2);
> -		val += 2;
> -	}
> -
> -	return sz;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
> -
> -/**
> - * of_property_read_string - Find and read a string from a property
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @out_string:	pointer to null terminated return string, modified only if
> - *		return value is 0.
> - *
> - * Search for a property in a device tree node and retrieve a null
> - * terminated string value (pointer to data, not a copy). Returns 0 on
> - * success, -EINVAL if the property does not exist, -ENODATA if property
> - * does not have a value, and -EILSEQ if the string is not null-terminated
> - * within the length of the property data.
> - *
> - * The out_string pointer is modified only if a valid string can be decoded.
> - */
> -int of_property_read_string(const struct device_node *np, const char *propname,
> -				const char **out_string)
> -{
> -	const struct property *prop = of_find_property(np, propname, NULL);
> -	if (!prop)
> -		return -EINVAL;
> -	if (!prop->value)
> -		return -ENODATA;
> -	if (strnlen(prop->value, prop->length) >= prop->length)
> -		return -EILSEQ;
> -	*out_string = prop->value;
> -	return 0;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_string);
> -
> -/**
> - * of_property_match_string() - Find string in a list and return index
> - * @np: pointer to node containing string list property
> - * @propname: string list property name
> - * @string: pointer to string to search for in string list
> - *
> - * This function searches a string list property and returns the index
> - * of a specific string value.
> - */
> -int of_property_match_string(const struct device_node *np, const char *propname,
> -			     const char *string)
> -{
> -	const struct property *prop = of_find_property(np, propname, NULL);
> -	size_t l;
> -	int i;
> -	const char *p, *end;
> -
> -	if (!prop)
> -		return -EINVAL;
> -	if (!prop->value)
> -		return -ENODATA;
> -
> -	p = prop->value;
> -	end = p + prop->length;
> -
> -	for (i = 0; p < end; i++, p += l) {
> -		l = strnlen(p, end - p) + 1;
> -		if (p + l > end)
> -			return -EILSEQ;
> -		pr_debug("comparing %s with %s\n", string, p);
> -		if (strcmp(string, p) == 0)
> -			return i; /* Found it; return index */
> -	}
> -	return -ENODATA;
> -}
> -EXPORT_SYMBOL_GPL(of_property_match_string);
> -
> -/**
> - * of_property_read_string_helper() - Utility helper for parsing string properties
> - * @np:		device node from which the property value is to be read.
> - * @propname:	name of the property to be searched.
> - * @out_strs:	output array of string pointers.
> - * @sz:		number of array elements to read.
> - * @skip:	Number of strings to skip over at beginning of list.
> - *
> - * Don't call this function directly. It is a utility helper for the
> - * of_property_read_string*() family of functions.
> - */
> -int of_property_read_string_helper(const struct device_node *np,
> -				   const char *propname, const char **out_strs,
> -				   size_t sz, int skip)
> -{
> -	const struct property *prop = of_find_property(np, propname, NULL);
> -	int l = 0, i = 0;
> -	const char *p, *end;
> -
> -	if (!prop)
> -		return -EINVAL;
> -	if (!prop->value)
> -		return -ENODATA;
> -	p = prop->value;
> -	end = p + prop->length;
> -
> -	for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
> -		l = strnlen(p, end - p) + 1;
> -		if (p + l > end)
> -			return -EILSEQ;
> -		if (out_strs && i >= skip)
> -			*out_strs++ = p;
> -	}
> -	i -= skip;
> -	return i <= 0 ? -ENODATA : i;
> -}
> -EXPORT_SYMBOL_GPL(of_property_read_string_helper);
> -
>  void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
>  {
>  	int i;
> @@ -2180,47 +1759,6 @@ int of_alias_get_highest_id(const char *stem)
>  }
>  EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
>  
> -const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
> -			       u32 *pu)
> -{
> -	const void *curv = cur;
> -
> -	if (!prop)
> -		return NULL;
> -
> -	if (!cur) {
> -		curv = prop->value;
> -		goto out_val;
> -	}
> -
> -	curv += sizeof(*cur);
> -	if (curv >= prop->value + prop->length)
> -		return NULL;
> -
> -out_val:
> -	*pu = be32_to_cpup(curv);
> -	return curv;
> -}
> -EXPORT_SYMBOL_GPL(of_prop_next_u32);
> -
> -const char *of_prop_next_string(struct property *prop, const char *cur)
> -{
> -	const void *curv = cur;
> -
> -	if (!prop)
> -		return NULL;
> -
> -	if (!cur)
> -		return prop->value;
> -
> -	curv += strlen(cur) + 1;
> -	if (curv >= prop->value + prop->length)
> -		return NULL;
> -
> -	return curv;
> -}
> -EXPORT_SYMBOL_GPL(of_prop_next_string);
> -
>  /**
>   * of_console_check() - Test and setup console for DT setup
>   * @dn - Pointer to device node
> @@ -2295,243 +1833,3 @@ int of_find_last_cache_level(unsigned int cpu)
>  
>  	return cache_level;
>  }
> -
> -/**
> - * of_graph_parse_endpoint() - parse common endpoint node properties
> - * @node: pointer to endpoint device_node
> - * @endpoint: pointer to the OF endpoint data structure
> - *
> - * The caller should hold a reference to @node.
> - */
> -int of_graph_parse_endpoint(const struct device_node *node,
> -			    struct of_endpoint *endpoint)
> -{
> -	struct device_node *port_node = of_get_parent(node);
> -
> -	WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
> -		  __func__, node->full_name);
> -
> -	memset(endpoint, 0, sizeof(*endpoint));
> -
> -	endpoint->local_node = node;
> -	/*
> -	 * It doesn't matter whether the two calls below succeed.
> -	 * If they don't then the default value 0 is used.
> -	 */
> -	of_property_read_u32(port_node, "reg", &endpoint->port);
> -	of_property_read_u32(node, "reg", &endpoint->id);
> -
> -	of_node_put(port_node);
> -
> -	return 0;
> -}
> -EXPORT_SYMBOL(of_graph_parse_endpoint);
> -
> -/**
> - * of_graph_get_port_by_id() - get the port matching a given id
> - * @parent: pointer to the parent device node
> - * @id: id of the port
> - *
> - * Return: A 'port' node pointer with refcount incremented. The caller
> - * has to use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> -{
> -	struct device_node *node, *port;
> -
> -	node = of_get_child_by_name(parent, "ports");
> -	if (node)
> -		parent = node;
> -
> -	for_each_child_of_node(parent, port) {
> -		u32 port_id = 0;
> -
> -		if (of_node_cmp(port->name, "port") != 0)
> -			continue;
> -		of_property_read_u32(port, "reg", &port_id);
> -		if (id == port_id)
> -			break;
> -	}
> -
> -	of_node_put(node);
> -
> -	return port;
> -}
> -EXPORT_SYMBOL(of_graph_get_port_by_id);
> -
> -/**
> - * of_graph_get_next_endpoint() - get next endpoint node
> - * @parent: pointer to the parent device node
> - * @prev: previous endpoint node, or NULL to get first
> - *
> - * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> - * of the passed @prev node is decremented.
> - */
> -struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> -					struct device_node *prev)
> -{
> -	struct device_node *endpoint;
> -	struct device_node *port;
> -
> -	if (!parent)
> -		return NULL;
> -
> -	/*
> -	 * Start by locating the port node. If no previous endpoint is specified
> -	 * search for the first port node, otherwise get the previous endpoint
> -	 * parent port node.
> -	 */
> -	if (!prev) {
> -		struct device_node *node;
> -
> -		node = of_get_child_by_name(parent, "ports");
> -		if (node)
> -			parent = node;
> -
> -		port = of_get_child_by_name(parent, "port");
> -		of_node_put(node);
> -
> -		if (!port) {
> -			pr_err("graph: no port node found in %s\n",
> -			       parent->full_name);
> -			return NULL;
> -		}
> -	} else {
> -		port = of_get_parent(prev);
> -		if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
> -			      __func__, prev->full_name))
> -			return NULL;
> -	}
> -
> -	while (1) {
> -		/*
> -		 * Now that we have a port node, get the next endpoint by
> -		 * getting the next child. If the previous endpoint is NULL this
> -		 * will return the first child.
> -		 */
> -		endpoint = of_get_next_child(port, prev);
> -		if (endpoint) {
> -			of_node_put(port);
> -			return endpoint;
> -		}
> -
> -		/* No more endpoints under this port, try the next one. */
> -		prev = NULL;
> -
> -		do {
> -			port = of_get_next_child(parent, port);
> -			if (!port)
> -				return NULL;
> -		} while (of_node_cmp(port->name, "port"));
> -	}
> -}
> -EXPORT_SYMBOL(of_graph_get_next_endpoint);
> -
> -/**
> - * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
> - * @parent: pointer to the parent device node
> - * @port_reg: identifier (value of reg property) of the parent port node
> - * @reg: identifier (value of reg property) of the endpoint node
> - *
> - * Return: An 'endpoint' node pointer which is identified by reg and at the same
> - * is the child of a port node identified by port_reg. reg and port_reg are
> - * ignored when they are -1.
> - */
> -struct device_node *of_graph_get_endpoint_by_regs(
> -	const struct device_node *parent, int port_reg, int reg)
> -{
> -	struct of_endpoint endpoint;
> -	struct device_node *node = NULL;
> -
> -	for_each_endpoint_of_node(parent, node) {
> -		of_graph_parse_endpoint(node, &endpoint);
> -		if (((port_reg == -1) || (endpoint.port == port_reg)) &&
> -			((reg == -1) || (endpoint.id == reg)))
> -			return node;
> -	}
> -
> -	return NULL;
> -}
> -EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
> -
> -/**
> - * of_graph_get_remote_port_parent() - get remote port's parent node
> - * @node: pointer to a local endpoint device_node
> - *
> - * Return: Remote device node associated with remote endpoint node linked
> - *	   to @node. Use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_remote_port_parent(
> -			       const struct device_node *node)
> -{
> -	struct device_node *np;
> -	unsigned int depth;
> -
> -	/* Get remote endpoint node. */
> -	np = of_parse_phandle(node, "remote-endpoint", 0);
> -
> -	/* Walk 3 levels up only if there is 'ports' node. */
> -	for (depth = 3; depth && np; depth--) {
> -		np = of_get_next_parent(np);
> -		if (depth == 2 && of_node_cmp(np->name, "ports"))
> -			break;
> -	}
> -	return np;
> -}
> -EXPORT_SYMBOL(of_graph_get_remote_port_parent);
> -
> -/**
> - * of_graph_get_remote_port() - get remote port node
> - * @node: pointer to a local endpoint device_node
> - *
> - * Return: Remote port node associated with remote endpoint node linked
> - *	   to @node. Use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_remote_port(const struct device_node *node)
> -{
> -	struct device_node *np;
> -
> -	/* Get remote endpoint node. */
> -	np = of_parse_phandle(node, "remote-endpoint", 0);
> -	if (!np)
> -		return NULL;
> -	return of_get_next_parent(np);
> -}
> -EXPORT_SYMBOL(of_graph_get_remote_port);
> -
> -/**
> - * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
> - * @node: pointer to parent device_node containing graph port/endpoint
> - * @port: identifier (value of reg property) of the parent port node
> - * @endpoint: identifier (value of reg property) of the endpoint node
> - *
> - * Return: Remote device node associated with remote endpoint node linked
> - *	   to @node. Use of_node_put() on it when done.
> - */
> -struct device_node *of_graph_get_remote_node(const struct device_node *node,
> -					     u32 port, u32 endpoint)
> -{
> -	struct device_node *endpoint_node, *remote;
> -
> -	endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
> -	if (!endpoint_node) {
> -		pr_debug("no valid endpoint (%d, %d) for node %s\n",
> -			 port, endpoint, node->full_name);
> -		return NULL;
> -	}
> -
> -	remote = of_graph_get_remote_port_parent(endpoint_node);
> -	of_node_put(endpoint_node);
> -	if (!remote) {
> -		pr_debug("no valid remote node\n");
> -		return NULL;
> -	}
> -
> -	if (!of_device_is_available(remote)) {
> -		pr_debug("not available for remote node\n");
> -		return NULL;
> -	}
> -
> -	return remote;
> -}
> -EXPORT_SYMBOL(of_graph_get_remote_node);
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> new file mode 100644
> index 0000000..afcf00a
> --- /dev/null
> +++ b/drivers/of/property.c
> @@ -0,0 +1,727 @@
> +/*
> + * drivers/of/property.c - Devicetree properties and graphs.

    * drivers/of/property.c - Procedures for accessing and interpreting
    * Devicetree properties and graphs.
    *
    * Initially created by copying procedures from drivers/of/base.c

The reference to base.c provides a documentation trail to all of the
earlier git commits that created and modified the procedures.

It would also be useful to say what procedures do and do not belong
in this file.  My understanding is that the intent is for
drivers/of/property.c and drivers/acpi/property.c to provide the
respective functionality that is used by drivers/base/property.c
and that drivers also may directly access the procedures in
drivers/of/property.c.

-Frank

> + *
> + * Paul Mackerras	August 1996.
> + * Copyright (C) 1996-2005 Paul Mackerras.
> + *
> + *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
> + *    {engebret|bergner}@us.ibm.com
> + *
> + *  Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
> + *
> + *  Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
> + *  Grant Likely.
> + *
> + *      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/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/string.h>
> +
> +#include "of_private.h"
> +/**
> + * of_property_count_elems_of_size - Count the number of elements in a property
> + *
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @elem_size:	size of the individual element
> + *
> + * Search for a property in a device node and count the number of elements of
> + * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
> + * property does not exist or its length does not match a multiple of elem_size
> + * and -ENODATA if the property does not have a value.
> + */
> +int of_property_count_elems_of_size(const struct device_node *np,
> +				const char *propname, int elem_size)
> +{
> +	struct property *prop = of_find_property(np, propname, NULL);
> +
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -ENODATA;
> +
> +	if (prop->length % elem_size != 0) {
> +		pr_err("size of %s in node %s is not a multiple of %d\n",
> +		       propname, np->full_name, elem_size);
> +		return -EINVAL;
> +	}
> +
> +	return prop->length / elem_size;
> +}
> +EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
> +
> +/**
> + * of_find_property_value_of_size
> + *
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @min:	minimum allowed length of property value
> + * @max:	maximum allowed length of property value (0 means unlimited)
> + * @len:	if !=NULL, actual length is written to here
> + *
> + * Search for a property in a device node and valid the requested size.
> + * Returns the property value on success, -EINVAL if the property does not
> + *  exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
> + * property data is too small or too large.
> + *
> + */
> +static void *of_find_property_value_of_size(const struct device_node *np,
> +			const char *propname, u32 min, u32 max, size_t *len)
> +{
> +	struct property *prop = of_find_property(np, propname, NULL);
> +
> +	if (!prop)
> +		return ERR_PTR(-EINVAL);
> +	if (!prop->value)
> +		return ERR_PTR(-ENODATA);
> +	if (prop->length < min)
> +		return ERR_PTR(-EOVERFLOW);
> +	if (max && prop->length > max)
> +		return ERR_PTR(-EOVERFLOW);
> +
> +	if (len)
> +		*len = prop->length;
> +
> +	return prop->value;
> +}
> +
> +/**
> + * of_property_read_u32_index - Find and read a u32 from a multi-value property.
> + *
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @index:	index of the u32 in the list of values
> + * @out_value:	pointer to return value, modified only if no error.
> + *
> + * Search for a property in a device node and read nth 32-bit value from
> + * it. Returns 0 on success, -EINVAL if the property does not exist,
> + * -ENODATA if property does not have a value, and -EOVERFLOW if the
> + * property data isn't large enough.
> + *
> + * The out_value is modified only if a valid u32 value can be decoded.
> + */
> +int of_property_read_u32_index(const struct device_node *np,
> +				       const char *propname,
> +				       u32 index, u32 *out_value)
> +{
> +	const u32 *val = of_find_property_value_of_size(np, propname,
> +					((index + 1) * sizeof(*out_value)),
> +					0,
> +					NULL);
> +
> +	if (IS_ERR(val))
> +		return PTR_ERR(val);
> +
> +	*out_value = be32_to_cpup(((__be32 *)val) + index);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_u32_index);
> +
> +/**
> + * of_property_read_variable_u8_array - Find and read an array of u8 from a
> + * property, with bounds on the minimum and maximum array size.
> + *
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @out_values:	pointer to return value, modified only if return value is 0.
> + * @sz_min:	minimum number of array elements to read
> + * @sz_max:	maximum number of array elements to read, if zero there is no
> + *		upper limit on the number of elements in the dts entry but only
> + *		sz_min will be read.
> + *
> + * Search for a property in a device node and read 8-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * dts entry of array should be like:
> + *	property = /bits/ 8 <0x50 0x60 0x70>;
> + *
> + * The out_values is modified only if a valid u8 value can be decoded.
> + */
> +int of_property_read_variable_u8_array(const struct device_node *np,
> +					const char *propname, u8 *out_values,
> +					size_t sz_min, size_t sz_max)
> +{
> +	size_t sz, count;
> +	const u8 *val = of_find_property_value_of_size(np, propname,
> +						(sz_min * sizeof(*out_values)),
> +						(sz_max * sizeof(*out_values)),
> +						&sz);
> +
> +	if (IS_ERR(val))
> +		return PTR_ERR(val);
> +
> +	if (!sz_max)
> +		sz = sz_min;
> +	else
> +		sz /= sizeof(*out_values);
> +
> +	count = sz;
> +	while (count--)
> +		*out_values++ = *val++;
> +
> +	return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
> +
> +/**
> + * of_property_read_variable_u16_array - Find and read an array of u16 from a
> + * property, with bounds on the minimum and maximum array size.
> + *
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @out_values:	pointer to return value, modified only if return value is 0.
> + * @sz_min:	minimum number of array elements to read
> + * @sz_max:	maximum number of array elements to read, if zero there is no
> + *		upper limit on the number of elements in the dts entry but only
> + *		sz_min will be read.
> + *
> + * Search for a property in a device node and read 16-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * dts entry of array should be like:
> + *	property = /bits/ 16 <0x5000 0x6000 0x7000>;
> + *
> + * The out_values is modified only if a valid u16 value can be decoded.
> + */
> +int of_property_read_variable_u16_array(const struct device_node *np,
> +					const char *propname, u16 *out_values,
> +					size_t sz_min, size_t sz_max)
> +{
> +	size_t sz, count;
> +	const __be16 *val = of_find_property_value_of_size(np, propname,
> +						(sz_min * sizeof(*out_values)),
> +						(sz_max * sizeof(*out_values)),
> +						&sz);
> +
> +	if (IS_ERR(val))
> +		return PTR_ERR(val);
> +
> +	if (!sz_max)
> +		sz = sz_min;
> +	else
> +		sz /= sizeof(*out_values);
> +
> +	count = sz;
> +	while (count--)
> +		*out_values++ = be16_to_cpup(val++);
> +
> +	return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
> +
> +/**
> + * of_property_read_variable_u32_array - Find and read an array of 32 bit
> + * integers from a property, with bounds on the minimum and maximum array size.
> + *
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @out_values:	pointer to return value, modified only if return value is 0.
> + * @sz_min:	minimum number of array elements to read
> + * @sz_max:	maximum number of array elements to read, if zero there is no
> + *		upper limit on the number of elements in the dts entry but only
> + *		sz_min will be read.
> + *
> + * Search for a property in a device node and read 32-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * The out_values is modified only if a valid u32 value can be decoded.
> + */
> +int of_property_read_variable_u32_array(const struct device_node *np,
> +			       const char *propname, u32 *out_values,
> +			       size_t sz_min, size_t sz_max)
> +{
> +	size_t sz, count;
> +	const __be32 *val = of_find_property_value_of_size(np, propname,
> +						(sz_min * sizeof(*out_values)),
> +						(sz_max * sizeof(*out_values)),
> +						&sz);
> +
> +	if (IS_ERR(val))
> +		return PTR_ERR(val);
> +
> +	if (!sz_max)
> +		sz = sz_min;
> +	else
> +		sz /= sizeof(*out_values);
> +
> +	count = sz;
> +	while (count--)
> +		*out_values++ = be32_to_cpup(val++);
> +
> +	return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
> +
> +/**
> + * of_property_read_u64 - Find and read a 64 bit integer from a property
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @out_value:	pointer to return value, modified only if return value is 0.
> + *
> + * Search for a property in a device node and read a 64-bit value from
> + * it. Returns 0 on success, -EINVAL if the property does not exist,
> + * -ENODATA if property does not have a value, and -EOVERFLOW if the
> + * property data isn't large enough.
> + *
> + * The out_value is modified only if a valid u64 value can be decoded.
> + */
> +int of_property_read_u64(const struct device_node *np, const char *propname,
> +			 u64 *out_value)
> +{
> +	const __be32 *val = of_find_property_value_of_size(np, propname,
> +						sizeof(*out_value),
> +						0,
> +						NULL);
> +
> +	if (IS_ERR(val))
> +		return PTR_ERR(val);
> +
> +	*out_value = of_read_number(val, 2);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_u64);
> +
> +/**
> + * of_property_read_variable_u64_array - Find and read an array of 64 bit
> + * integers from a property, with bounds on the minimum and maximum array size.
> + *
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @out_values:	pointer to return value, modified only if return value is 0.
> + * @sz_min:	minimum number of array elements to read
> + * @sz_max:	maximum number of array elements to read, if zero there is no
> + *		upper limit on the number of elements in the dts entry but only
> + *		sz_min will be read.
> + *
> + * Search for a property in a device node and read 64-bit value(s) from
> + * it. Returns number of elements read on success, -EINVAL if the property
> + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
> + * if the property data is smaller than sz_min or longer than sz_max.
> + *
> + * The out_values is modified only if a valid u64 value can be decoded.
> + */
> +int of_property_read_variable_u64_array(const struct device_node *np,
> +			       const char *propname, u64 *out_values,
> +			       size_t sz_min, size_t sz_max)
> +{
> +	size_t sz, count;
> +	const __be32 *val = of_find_property_value_of_size(np, propname,
> +						(sz_min * sizeof(*out_values)),
> +						(sz_max * sizeof(*out_values)),
> +						&sz);
> +
> +	if (IS_ERR(val))
> +		return PTR_ERR(val);
> +
> +	if (!sz_max)
> +		sz = sz_min;
> +	else
> +		sz /= sizeof(*out_values);
> +
> +	count = sz;
> +	while (count--) {
> +		*out_values++ = of_read_number(val, 2);
> +		val += 2;
> +	}
> +
> +	return sz;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
> +
> +/**
> + * of_property_read_string - Find and read a string from a property
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @out_string:	pointer to null terminated return string, modified only if
> + *		return value is 0.
> + *
> + * Search for a property in a device tree node and retrieve a null
> + * terminated string value (pointer to data, not a copy). Returns 0 on
> + * success, -EINVAL if the property does not exist, -ENODATA if property
> + * does not have a value, and -EILSEQ if the string is not null-terminated
> + * within the length of the property data.
> + *
> + * The out_string pointer is modified only if a valid string can be decoded.
> + */
> +int of_property_read_string(const struct device_node *np, const char *propname,
> +				const char **out_string)
> +{
> +	const struct property *prop = of_find_property(np, propname, NULL);
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -ENODATA;
> +	if (strnlen(prop->value, prop->length) >= prop->length)
> +		return -EILSEQ;
> +	*out_string = prop->value;
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_string);
> +
> +/**
> + * of_property_match_string() - Find string in a list and return index
> + * @np: pointer to node containing string list property
> + * @propname: string list property name
> + * @string: pointer to string to search for in string list
> + *
> + * This function searches a string list property and returns the index
> + * of a specific string value.
> + */
> +int of_property_match_string(const struct device_node *np, const char *propname,
> +			     const char *string)
> +{
> +	const struct property *prop = of_find_property(np, propname, NULL);
> +	size_t l;
> +	int i;
> +	const char *p, *end;
> +
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -ENODATA;
> +
> +	p = prop->value;
> +	end = p + prop->length;
> +
> +	for (i = 0; p < end; i++, p += l) {
> +		l = strnlen(p, end - p) + 1;
> +		if (p + l > end)
> +			return -EILSEQ;
> +		pr_debug("comparing %s with %s\n", string, p);
> +		if (strcmp(string, p) == 0)
> +			return i; /* Found it; return index */
> +	}
> +	return -ENODATA;
> +}
> +EXPORT_SYMBOL_GPL(of_property_match_string);
> +
> +/**
> + * of_property_read_string_helper() - Utility helper for parsing string properties
> + * @np:		device node from which the property value is to be read.
> + * @propname:	name of the property to be searched.
> + * @out_strs:	output array of string pointers.
> + * @sz:		number of array elements to read.
> + * @skip:	Number of strings to skip over at beginning of list.
> + *
> + * Don't call this function directly. It is a utility helper for the
> + * of_property_read_string*() family of functions.
> + */
> +int of_property_read_string_helper(const struct device_node *np,
> +				   const char *propname, const char **out_strs,
> +				   size_t sz, int skip)
> +{
> +	const struct property *prop = of_find_property(np, propname, NULL);
> +	int l = 0, i = 0;
> +	const char *p, *end;
> +
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -ENODATA;
> +	p = prop->value;
> +	end = p + prop->length;
> +
> +	for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
> +		l = strnlen(p, end - p) + 1;
> +		if (p + l > end)
> +			return -EILSEQ;
> +		if (out_strs && i >= skip)
> +			*out_strs++ = p;
> +	}
> +	i -= skip;
> +	return i <= 0 ? -ENODATA : i;
> +}
> +EXPORT_SYMBOL_GPL(of_property_read_string_helper);
> +
> +const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
> +			       u32 *pu)
> +{
> +	const void *curv = cur;
> +
> +	if (!prop)
> +		return NULL;
> +
> +	if (!cur) {
> +		curv = prop->value;
> +		goto out_val;
> +	}
> +
> +	curv += sizeof(*cur);
> +	if (curv >= prop->value + prop->length)
> +		return NULL;
> +
> +out_val:
> +	*pu = be32_to_cpup(curv);
> +	return curv;
> +}
> +EXPORT_SYMBOL_GPL(of_prop_next_u32);
> +
> +const char *of_prop_next_string(struct property *prop, const char *cur)
> +{
> +	const void *curv = cur;
> +
> +	if (!prop)
> +		return NULL;
> +
> +	if (!cur)
> +		return prop->value;
> +
> +	curv += strlen(cur) + 1;
> +	if (curv >= prop->value + prop->length)
> +		return NULL;
> +
> +	return curv;
> +}
> +EXPORT_SYMBOL_GPL(of_prop_next_string);
> +
> +/**
> + * of_graph_parse_endpoint() - parse common endpoint node properties
> + * @node: pointer to endpoint device_node
> + * @endpoint: pointer to the OF endpoint data structure
> + *
> + * The caller should hold a reference to @node.
> + */
> +int of_graph_parse_endpoint(const struct device_node *node,
> +			    struct of_endpoint *endpoint)
> +{
> +	struct device_node *port_node = of_get_parent(node);
> +
> +	WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
> +		  __func__, node->full_name);
> +
> +	memset(endpoint, 0, sizeof(*endpoint));
> +
> +	endpoint->local_node = node;
> +	/*
> +	 * It doesn't matter whether the two calls below succeed.
> +	 * If they don't then the default value 0 is used.
> +	 */
> +	of_property_read_u32(port_node, "reg", &endpoint->port);
> +	of_property_read_u32(node, "reg", &endpoint->id);
> +
> +	of_node_put(port_node);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(of_graph_parse_endpoint);
> +
> +/**
> + * of_graph_get_port_by_id() - get the port matching a given id
> + * @parent: pointer to the parent device node
> + * @id: id of the port
> + *
> + * Return: A 'port' node pointer with refcount incremented. The caller
> + * has to use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
> +{
> +	struct device_node *node, *port;
> +
> +	node = of_get_child_by_name(parent, "ports");
> +	if (node)
> +		parent = node;
> +
> +	for_each_child_of_node(parent, port) {
> +		u32 port_id = 0;
> +
> +		if (of_node_cmp(port->name, "port") != 0)
> +			continue;
> +		of_property_read_u32(port, "reg", &port_id);
> +		if (id == port_id)
> +			break;
> +	}
> +
> +	of_node_put(node);
> +
> +	return port;
> +}
> +EXPORT_SYMBOL(of_graph_get_port_by_id);
> +
> +/**
> + * of_graph_get_next_endpoint() - get next endpoint node
> + * @parent: pointer to the parent device node
> + * @prev: previous endpoint node, or NULL to get first
> + *
> + * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> + * of the passed @prev node is decremented.
> + */
> +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> +					struct device_node *prev)
> +{
> +	struct device_node *endpoint;
> +	struct device_node *port;
> +
> +	if (!parent)
> +		return NULL;
> +
> +	/*
> +	 * Start by locating the port node. If no previous endpoint is specified
> +	 * search for the first port node, otherwise get the previous endpoint
> +	 * parent port node.
> +	 */
> +	if (!prev) {
> +		struct device_node *node;
> +
> +		node = of_get_child_by_name(parent, "ports");
> +		if (node)
> +			parent = node;
> +
> +		port = of_get_child_by_name(parent, "port");
> +		of_node_put(node);
> +
> +		if (!port) {
> +			pr_err("graph: no port node found in %s\n",
> +			       parent->full_name);
> +			return NULL;
> +		}
> +	} else {
> +		port = of_get_parent(prev);
> +		if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
> +			      __func__, prev->full_name))
> +			return NULL;
> +	}
> +
> +	while (1) {
> +		/*
> +		 * Now that we have a port node, get the next endpoint by
> +		 * getting the next child. If the previous endpoint is NULL this
> +		 * will return the first child.
> +		 */
> +		endpoint = of_get_next_child(port, prev);
> +		if (endpoint) {
> +			of_node_put(port);
> +			return endpoint;
> +		}
> +
> +		/* No more endpoints under this port, try the next one. */
> +		prev = NULL;
> +
> +		do {
> +			port = of_get_next_child(parent, port);
> +			if (!port)
> +				return NULL;
> +		} while (of_node_cmp(port->name, "port"));
> +	}
> +}
> +EXPORT_SYMBOL(of_graph_get_next_endpoint);
> +
> +/**
> + * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
> + * @parent: pointer to the parent device node
> + * @port_reg: identifier (value of reg property) of the parent port node
> + * @reg: identifier (value of reg property) of the endpoint node
> + *
> + * Return: An 'endpoint' node pointer which is identified by reg and at the same
> + * is the child of a port node identified by port_reg. reg and port_reg are
> + * ignored when they are -1.
> + */
> +struct device_node *of_graph_get_endpoint_by_regs(
> +	const struct device_node *parent, int port_reg, int reg)
> +{
> +	struct of_endpoint endpoint;
> +	struct device_node *node = NULL;
> +
> +	for_each_endpoint_of_node(parent, node) {
> +		of_graph_parse_endpoint(node, &endpoint);
> +		if (((port_reg == -1) || (endpoint.port == port_reg)) &&
> +			((reg == -1) || (endpoint.id == reg)))
> +			return node;
> +	}
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
> +
> +/**
> + * of_graph_get_remote_port_parent() - get remote port's parent node
> + * @node: pointer to a local endpoint device_node
> + *
> + * Return: Remote device node associated with remote endpoint node linked
> + *	   to @node. Use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_remote_port_parent(
> +			       const struct device_node *node)
> +{
> +	struct device_node *np;
> +	unsigned int depth;
> +
> +	/* Get remote endpoint node. */
> +	np = of_parse_phandle(node, "remote-endpoint", 0);
> +
> +	/* Walk 3 levels up only if there is 'ports' node. */
> +	for (depth = 3; depth && np; depth--) {
> +		np = of_get_next_parent(np);
> +		if (depth == 2 && of_node_cmp(np->name, "ports"))
> +			break;
> +	}
> +	return np;
> +}
> +EXPORT_SYMBOL(of_graph_get_remote_port_parent);
> +
> +/**
> + * of_graph_get_remote_port() - get remote port node
> + * @node: pointer to a local endpoint device_node
> + *
> + * Return: Remote port node associated with remote endpoint node linked
> + *	   to @node. Use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_remote_port(const struct device_node *node)
> +{
> +	struct device_node *np;
> +
> +	/* Get remote endpoint node. */
> +	np = of_parse_phandle(node, "remote-endpoint", 0);
> +	if (!np)
> +		return NULL;
> +	return of_get_next_parent(np);
> +}
> +EXPORT_SYMBOL(of_graph_get_remote_port);
> +
> +/**
> + * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
> + * @node: pointer to parent device_node containing graph port/endpoint
> + * @port: identifier (value of reg property) of the parent port node
> + * @endpoint: identifier (value of reg property) of the endpoint node
> + *
> + * Return: Remote device node associated with remote endpoint node linked
> + *	   to @node. Use of_node_put() on it when done.
> + */
> +struct device_node *of_graph_get_remote_node(const struct device_node *node,
> +					     u32 port, u32 endpoint)
> +{
> +	struct device_node *endpoint_node, *remote;
> +
> +	endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
> +	if (!endpoint_node) {
> +		pr_debug("no valid endpoint (%d, %d) for node %s\n",
> +			 port, endpoint, node->full_name);
> +		return NULL;
> +	}
> +
> +	remote = of_graph_get_remote_port_parent(endpoint_node);
> +	of_node_put(endpoint_node);
> +	if (!remote) {
> +		pr_debug("no valid remote node\n");
> +		return NULL;
> +	}
> +
> +	if (!of_device_is_available(remote)) {
> +		pr_debug("not available for remote node\n");
> +		return NULL;
> +	}
> +
> +	return remote;
> +}
> +EXPORT_SYMBOL(of_graph_get_remote_node);
> 


^ permalink raw reply

* Re: [PATCH v6 02/39] [media] dt-bindings: Add bindings for i.MX media driver
From: Rob Herring @ 2017-03-29  0:21 UTC (permalink / raw)
  To: Steve Longerbeam
  Cc: Mark Rutland, Shawn Guo, kernel@pengutronix.de, Fabio Estevam,
	Russell King, Mauro Carvalho Chehab, Hans Verkuil, Nick Dyer,
	markus.heiser, Philipp Zabel, Laurent Pinchart, Benoit Parrot,
	Geert Uytterhoeven, Arnd Bergmann, Sudip Mukherjee, Minghsiu Tsai,
	tiffany lin, Jean-Christophe Trotin, Simon Horman
In-Reply-To: <1490661656-10318-3-git-send-email-steve_longerbeam@mentor.com>

On Mon, Mar 27, 2017 at 7:40 PM, Steve Longerbeam <slongerbeam@gmail.com> wrote:
> Add bindings documentation for the i.MX media driver.
>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  Documentation/devicetree/bindings/media/imx.txt | 74 +++++++++++++++++++++++++
>  1 file changed, 74 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/imx.txt
>
> diff --git a/Documentation/devicetree/bindings/media/imx.txt b/Documentation/devicetree/bindings/media/imx.txt
> new file mode 100644
> index 0000000..3059c06
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/imx.txt
> @@ -0,0 +1,74 @@
> +Freescale i.MX Media Video Device
> +=================================
> +
> +Video Media Controller node
> +---------------------------
> +
> +This is the media controller node for video capture support. It is a
> +virtual device that lists the camera serial interface nodes that the
> +media device will control.
> +
> +Required properties:
> +- compatible : "fsl,imx-capture-subsystem";
> +- ports      : Should contain a list of phandles pointing to camera
> +               sensor interface ports of IPU devices
> +
> +example:
> +
> +capture-subsystem {
> +       compatible = "fsl,imx-capture-subsystem";
> +       ports = <&ipu1_csi0>, <&ipu1_csi1>;
> +};
> +
> +fim child node
> +--------------
> +
> +This is an optional child node of the ipu_csi port nodes. If present and
> +available, it enables the Frame Interval Monitor. Its properties can be
> +used to modify the method in which the FIM measures frame intervals.
> +Refer to Documentation/media/v4l-drivers/imx.rst for more info on the
> +Frame Interval Monitor.
> +
> +Optional properties:
> +- fsl,input-capture-channel: an input capture channel and channel flags,
> +                            specified as <chan flags>. The channel number
> +                            must be 0 or 1. The flags can be
> +                            IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, or
> +                            IRQ_TYPE_EDGE_BOTH, and specify which input
> +                            capture signal edge will trigger the input
> +                            capture event. If an input capture channel is
> +                            specified, the FIM will use this method to
> +                            measure frame intervals instead of via the EOF
> +                            interrupt. The input capture method is much
> +                            preferred over EOF as it is not subject to
> +                            interrupt latency errors. However it requires
> +                            routing the VSYNC or FIELD output signals of
> +                            the camera sensor to one of the i.MX input
> +                            capture pads (SD1_DAT0, SD1_DAT1), which also
> +                            gives up support for SD1.
> +
> +
> +mipi_csi2 node
> +--------------
> +
> +This is the device node for the MIPI CSI-2 Receiver, required for MIPI
> +CSI-2 sensors.
> +
> +Required properties:
> +- compatible   : "fsl,imx6-mipi-csi2", "snps,dw-mipi-csi2";

As I mentioned in v5, there's a DW CSI2 binding in progress. This
needs to be based on that.

Rob

^ permalink raw reply

* Re: [PATCH v2 1/5] dt-bindings: Document STM32 CRC bindings
From: Rob Herring @ 2017-03-29  0:28 UTC (permalink / raw)
  To: Fabien Dessenne
  Cc: Herbert Xu, David S . Miller, Mark Rutland, Maxime Coquelin,
	Alexandre Torgue, Russell King, linux-crypto, devicetree,
	linux-arm-kernel, Benjamin Gaignard
In-Reply-To: <1490109211-4869-2-git-send-email-fabien.dessenne@st.com>

On Tue, Mar 21, 2017 at 04:13:27PM +0100, Fabien Dessenne wrote:
> Document device tree bindings for the STM32 CRC (crypto CRC32)
> 
> Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com>
> ---
>  .../devicetree/bindings/crypto/st,stm32-crc.txt          | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/crypto/st,stm32-crc.txt

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply

* Re: [PATCH v3 04/11] Documentation: DT: bindings: mfd: add A33 GPADC binding
From: Rob Herring @ 2017-03-29  0:31 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, mark.rutland-5wv7dgnIgG8,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, wens-jdAy2FN1RRM,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
	lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
	thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, icenowy-ymACFijhrKM
In-Reply-To: <20170321153611.16228-5-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

On Tue, Mar 21, 2017 at 04:36:04PM +0100, Quentin Schulz wrote:
> This patch adds documentation for the A33 GPADC binding.
> 
> Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
> 
> v3:
>   - fixed missing allwinner in front of compatible,
>   - updated compatible to allwinner,sun8i-a33-ths to better reflect the
>   datasheet's name,
>   - updated example's DT node name and label to ths,
> 
> added in v2
> 
>  .../devicetree/bindings/mfd/sun4i-gpadc.txt        | 59 ++++++++++++++++++++++
>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/sun4i-gpadc.txt

If you respin, "dt-bindings: mfd: ..." for the subject.

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

^ permalink raw reply

* Re: [PATCH v2 1/2] Documentation: dt-bindings: Document bindings for Aspeed AST2400/AST2500 ADC
From: Rob Herring @ 2017-03-29  0:33 UTC (permalink / raw)
  To: Rick Altherr
  Cc: openbmc, linux-kernel, devicetree, linux-iio, Hartmut Knaack,
	Lars-Peter Clausen, Mark Rutland, Jonathan Cameron,
	Peter Meerwald-Stadler
In-Reply-To: <20170321204828.31303-1-raltherr@google.com>

On Tue, Mar 21, 2017 at 01:48:27PM -0700, Rick Altherr wrote:
> Signed-off-by: Rick Altherr <raltherr@google.com>
> ---
> 
> Changes in v2:
> - Rewritten as an IIO ADC device
> 
>  .../devicetree/bindings/iio/adc/aspeed_adc.txt       | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply

* Re: [PATCH v6 02/39] [media] dt-bindings: Add bindings for i.MX media driver
From: Steve Longerbeam @ 2017-03-29  0:35 UTC (permalink / raw)
  To: Rob Herring, Steve Longerbeam
  Cc: Mark Rutland, Andrew-CT Chen (陳智迪),
	Minghsiu Tsai, Sakari Ailus, Nick Dyer, Songjun Wu, Hans Verkuil,
	Pavel Machek, Robert Jarzmik, devel, markus.heiser,
	Laurent Pinchart, shuah, Russell King, Geert Uytterhoeven,
	linux-media@vger.kernel.org, devicetree@vger.kernel.org,
	kernel@pengutronix.de, Arnd Bergmann, Mauro Carvalho Chehab,
	Benoit Parrot
In-Reply-To: <CAL_JsqJm_JjuVPcOBERCqsnjTDdNoKr9xRE9MXMO4ivxGath2Q@mail.gmail.com>



On 03/28/2017 05:21 PM, Rob Herring wrote:
> On Mon, Mar 27, 2017 at 7:40 PM, Steve Longerbeam <slongerbeam@gmail.com> wrote:
>> Add bindings documentation for the i.MX media driver.
>>
>> <snip>
>> +
>> +mipi_csi2 node
>> +--------------
>> +
>> +This is the device node for the MIPI CSI-2 Receiver, required for MIPI
>> +CSI-2 sensors.
>> +
>> +Required properties:
>> +- compatible   : "fsl,imx6-mipi-csi2", "snps,dw-mipi-csi2";
>
> As I mentioned in v5, there's a DW CSI2 binding in progress. This
> needs to be based on that.

Hi Rob, I'm not sure what you are asking me to do.

I assume if there's another binding doc in progress, it means
someone is working on another Synopsys DW CSI-2 subdevice driver.

Unfortunately I don't have the time to contribute and switch to
this other subdevice, and do test/debug.

For now I would prefer if this patchset is merged as is, and
then contribute/switch to another CSI-2 subdev later. It is
also getting very difficult managing all these patches (39 as
of this version), and I'd prefer not to spam the lists with
such large patchsets for too much longer.


Steve

^ permalink raw reply

* Re: [PATCH v1 1/7] devicetree: power: battery: Add properties for pre-charge and end-charge current
From: Rob Herring @ 2017-03-29  0:39 UTC (permalink / raw)
  To: Liam Breck
  Cc: Sebastian Reichel, Tony Lindgren, linux-pm-u79uwXL29TY76Z2rM5mHXA,
	Hans de Goede, devicetree-u79uwXL29TY76Z2rM5mHXA, Liam Breck
In-Reply-To: <20170321220921.5834-2-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>

On Tue, Mar 21, 2017 at 03:09:15PM -0700, Liam Breck wrote:
> From: Liam Breck <kernel-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
> 
> precharge-current-microamp and endcharge-current-microamp are used
> by battery chargers at the beginning and end of a charging cycle.
> 
> Depends-on: https://patchwork.kernel.org/patch/9633605/
> Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Signed-off-by: Liam Breck <kernel-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/power/supply/battery.txt | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/battery.txt b/Documentation/devicetree/bindings/power/supply/battery.txt
> index 53a68c0..494374a 100644
> --- a/Documentation/devicetree/bindings/power/supply/battery.txt
> +++ b/Documentation/devicetree/bindings/power/supply/battery.txt
> @@ -12,6 +12,8 @@ Optional Properties:
>   - voltage-min-design-microvolt: drained battery voltage
>   - energy-full-design-microwatt-hours: battery design energy
>   - charge-full-design-microamp-hours: battery design capacity
> + - precharge-current-microamp: current for pre-charge phase
> + - endcharge-current-microamp: current for charge termination phase

current is implied by microamp, so perhaps just pre-charge-microamp and 
end-charge-microamp.

I know little about batteries, but don't you also need to know when each 
phase starts/ends? 

I mainly ask because we just added the previous properties and now we're 
adding 2 more. While fine to add features to a driver one by one, we 
really shouldn't for bindings. The h/w is not evolving (in a month).

Rob
--
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 v1 1/7] devicetree: power: battery: Add properties for pre-charge and end-charge current
From: Rob Herring @ 2017-03-29  0:43 UTC (permalink / raw)
  To: Liam Breck
  Cc: Sebastian Reichel, Tony Lindgren, linux-pm, Hans de Goede,
	devicetree, Liam Breck
In-Reply-To: <CAKvHMgQt=C1tmfPz3pp_vwhc3b9DHKau2t=jwp3Rv2b2U6hsaQ@mail.gmail.com>

On Fri, Mar 24, 2017 at 05:34:26PM -0700, Liam Breck wrote:
> On Fri, Mar 24, 2017 at 2:01 AM, Sebastian Reichel <sre@kernel.org> wrote:
> > Hi,
> >
> > On Tue, Mar 21, 2017 at 03:09:15PM -0700, Liam Breck wrote:
> >> From: Liam Breck <kernel@networkimprov.net>
> >>
> >> precharge-current-microamp and endcharge-current-microamp are used
> >> by battery chargers at the beginning and end of a charging cycle.
> >>
> >> Depends-on: https://patchwork.kernel.org/patch/9633605/
> >> Cc: Rob Herring <robh@kernel.org>
> >> Cc: devicetree@vger.kernel.org
> >> Signed-off-by: Liam Breck <kernel@networkimprov.net>
> >
> > Acked-by: Sebastian Reichel <sre@kernel.org>
> >
> > I think it makes sense to merge this into the patch adding
> > simple-battery.

Agreed.

> 
> It would make sense, but it means a new _prop_precharge/endcharge
> patch in that patchset, and I am trying to constrain it at this stage.

Please make bindings complete as possible. You don't have to have the 
driver side.

Rob

^ permalink raw reply

* Re: [PATCH v1 2/7] devicetree: power: Add docs for TI BQ24190 battery charger
From: Rob Herring @ 2017-03-29  0:47 UTC (permalink / raw)
  To: Liam Breck
  Cc: Sebastian Reichel, Tony Lindgren, linux-pm-u79uwXL29TY76Z2rM5mHXA,
	Hans de Goede, devicetree-u79uwXL29TY76Z2rM5mHXA, Liam Breck
In-Reply-To: <20170321220921.5834-3-liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>

On Tue, Mar 21, 2017 at 03:09:16PM -0700, Liam Breck wrote:
> From: Liam Breck <kernel-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
> 
> Document monitored-battery and ti,system-minimum-microvolt properties.
> 
> Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Signed-off-by: Liam Breck <kernel-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn@public.gmane.org>
> ---
>  .../devicetree/bindings/power/supply/bq24190.txt   | 47 ++++++++++++++++++++++
>  1 file changed, 47 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/bq24190.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/bq24190.txt b/Documentation/devicetree/bindings/power/supply/bq24190.txt
> new file mode 100644
> index 0000000..d252d10
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/bq24190.txt
> @@ -0,0 +1,47 @@
> +Binding for TI BQ24190 Li-Ion Battery Charger
> +
> +Required properties:
> +- compatible: Should contain one of the following:
> +    * "ti,bq24190"
> +- reg: integer, I2C address of the device.
> +
> +Optional properties:
> +- monitored-battery: phandle of battery information devicetree node
> +    These battery properties are relevant:
> +    + precharge-current-microamp: maximum charge current during precharge
> +      phase (typically 20% of battery capacity).
> +    + endcharge-current-microamp: a charge cycle terminates when the
> +      battery voltage is above recharge threshold, and the current is below
> +      this setting (typically 10% of battery capacity).
> +    See Documentation/devicetree/bindings/power/supply/battery.txt

This isn't really relevant to the binding. The battery properties 
shouldn't vary with the charger.

> +- ti,system-minimum-microvolt: when power is connected and the battery
> +    is below minimum system voltage, the system will be regulated above this
> +    setting.
> +
> +Other features:
> +- Use gpio-hog to set the OTG pin high to enable 500mA charge current on USB SDP port.
> +
> +Example:
> +
> +bat: battery {
> +	compatible = "simple-battery";
> +	precharge-current-microamp = <256000>;
> +	endcharge-current-microamp = <128000>;
> +};
> +
> +bq24190 charger@6a {
> +	compatible = "ti,bq24190";
> +	reg = <0x6a>;
> +	// interrupt configuration here
> +	monitored-battery = <&bat>;
> +	ti,system-minimum-microvolt = <3200000>;
> +};
> +
> +&twl_gpio {
> +	otg {
> +		gpio-hog;
> +		gpios = <6 0>;
> +		output-high;
> +		line-name = "otg-gpio";
> +	};
> +};
> -- 
> 2.9.3
> 
--
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 v3] ASoC: Add support for Maxim Integrated MAX98927 Amplifier
From: Ryan Lee @ 2017-03-29  0:49 UTC (permalink / raw)
  To: Mark Brown
  Cc: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ, arnd-r2nGTMty4D4,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lars-Qo5EllUWu/uELgA04lAiVw, bardliao-Rasf1IRRPZFBDgjK7y7TUQ,
	nh6z-fFIq/eER6g8, KCHSU0-KrzQf0k3Iz9BDgjK7y7TUQ,
	axel.lin-8E1dMatC8ynQT0dZR+AlfA,
	romain.perier-ZGY8ohtN/8qB+jHODAdFcQ,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	dgreid-hpIqsD4AKlfQT0dZR+AlfA
In-Reply-To: <20170328163928.jtjnfzcd3turhhl7-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>

On Tue, Mar 28, 2017 at 9:39 AM, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> On Wed, Mar 29, 2017 at 12:32:28AM +0900, Ryan Lee wrote:
>> Signed-off-by: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
>
> Please stop sending patches in the middle of existing threads, it makes
> it hard to see new versions and for multi-patch serieses makes it hard
> to see what the current version of the series is.

I'm sorry to make it get confused. I'll resend it on the top.
--
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

* [PATCH v3] ASoC: Add support for Maxim Integrated MAX98927 Amplifier
From: Ryan Lee @ 2017-03-29  0:53 UTC (permalink / raw)
  To: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ, arnd-r2nGTMty4D4,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	lars-Qo5EllUWu/uELgA04lAiVw, bardliao-Rasf1IRRPZFBDgjK7y7TUQ,
	nh6z-fFIq/eER6g8, KCHSU0-KrzQf0k3Iz9BDgjK7y7TUQ,
	axel.lin-8E1dMatC8ynQT0dZR+AlfA,
	romain.perier-ZGY8ohtN/8qB+jHODAdFcQ,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: dgreid-hpIqsD4AKlfQT0dZR+AlfA,
	ryan.lee.maxim-Re5JQEeQqe8AvxtiuMwx3w

Signed-off-by: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
---

Changes since v3:
	* Combined MAX98926 and MAX98927 binding. Kept existing property name.

Changes since v2:
	* Removed local register read/write function to avoid duplication of ASoC core function.
	
 .../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                        | 826 +++++++++++++++++++++
 sound/soc/codecs/max98927.h                        | 267 +++++++
 7 files changed, 1141 insertions(+), 54 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/sound/max98925.txt
 delete mode 100644 Documentation/devicetree/bindings/sound/max98926.txt
 create mode 100755 Documentation/devicetree/bindings/sound/max9892x.txt
 mode change 100644 => 100755 sound/soc/codecs/Kconfig
 mode change 100644 => 100755 sound/soc/codecs/Makefile
 create mode 100755 sound/soc/codecs/max98927.c
 create mode 100755 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 27be63e..0000000
--- 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 0b7f4e4..0000000
--- 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 100755
index 0000000..f617159
--- /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
old mode 100644
new mode 100755
index e49e9da..cbdc8aa
--- 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
@@ -588,6 +589,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
old mode 100644
new mode 100755
index 1796cb9..187a639
--- 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
@@ -313,6 +314,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 100755
index 0000000..15f2192
--- /dev/null
+++ b/sound/soc/codecs/max98927.c
@@ -0,0 +1,826 @@
+/*
+ * 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 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;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		mode = MAX98927_PCM_MASTER_MODE_HYBRID;
+	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;
+
+	break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0020_PCM_MODE_CFG,
+		max98927->iface, max98927->iface);
+
+	/* pcm channel configuration */
+	if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J))
+		regmap_write(max98927->regmap,
+			MAX98927_R0018_PCM_RX_EN_A,
+			MAX98927_PCM_RX_CH0_EN|
+			MAX98927_PCM_RX_CH1_EN);
+
+	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 reg = MAX98927_R0022_PCM_CLK_SETUP;
+	int mask = MAX98927_PCM_CLK_SETUP_BSEL_MASK;
+	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, reg, 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;
+		max98927->ch_size = 16;
+		break;
+	case 24:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
+		max98927->ch_size = 24;
+		break;
+	case 32:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
+		max98927->ch_size = 32;
+		break;
+	default:
+		dev_err(codec->dev, "format unsupported %d",
+			params_format(params));
+		goto err;
+	}
+
+	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;
+	}
+	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 const char * const max98927_speaker_source_text[] = {
+	"i2s", "reserved", "tone", "pdm"
+};
+
+static const char * const max98927_monomix_output_text[] = {
+	"ch_0", "ch_1", "ch_1_2_div"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98927_boost_voltage,
+		MAX98927_R0040_BOOST_CTRL0, 0,
+		max98927_boost_voltage_text);
+
+static SOC_ENUM_SINGLE_DECL(max98927_spk_source,
+		MAX98927_R003B_SPK_SRC_SEL, 0,
+		max98927_speaker_source_text);
+
+static SOC_ENUM_SINGLE_DECL(max98927_monomix_output,
+		MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+		MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
+		max98927_monomix_output_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 Gain", MAX98927_R0036_AMP_VOL_CTRL,
+		0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
+		max98927_digital_tlv),
+	SOC_SINGLE("Amp DSP Enable", 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 EN", MAX98927_R0039_DRE_CTRL,
+		MAX98927_DRE_EN_SHIFT, 1, 0),
+	SOC_SINGLE("Amp Volume Location", MAX98927_R0036_AMP_VOL_CTRL,
+		MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
+	SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
+	SOC_ENUM("Speaker Source", max98927_spk_source),
+	SOC_ENUM("Monomix Output", max98927_monomix_output),
+};
+
+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);
+	int ret = 0, reg = 0;
+
+	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);
+
+	/* Check Revision ID */
+	ret = regmap_read(max98927->regmap,
+		MAX98927_R01FF_REV_ID, &reg);
+	if (ret < 0)
+		dev_err(codec->dev,
+			"Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
+	else
+		dev_info(codec->dev,
+			"MAX98927 revisionID: 0x%02X\n", reg);
+
+	/* 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 ret;
+}
+
+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;
+	struct max98927_priv *max98927 = NULL;
+
+	max98927 = devm_kzalloc(&i2c->dev,
+		sizeof(*max98927), GFP_KERNEL);
+
+	if (!max98927) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	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);
+		goto err;
+	}
+
+	/* 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;
+
+err:
+	if (max98927)
+		devm_kfree(&i2c->dev, max98927);
+	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 100755
index 0000000..e13e18a
--- /dev/null
+++ b/sound/soc/codecs/max98927.h
@@ -0,0 +1,267 @@
+/*
+ * 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_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_HYBRID (0x1 << 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_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.7.4

--
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] Add initial SX3000b platform related documentation to document tree
From: Rob Herring @ 2017-03-29  0:55 UTC (permalink / raw)
  To: Amit Kama IL
  Cc: corbet@lwn.net, ralf@linux-mips.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-mips@linux-mips.org,
	tglx@linutronix.de, jason@lakedaemon.net, marc.zyngier@arm.com,
	linux-doc@vger.kernel.org
In-Reply-To: <AM4PR0201MB21799759E18C64A7032A2C3EE43C0@AM4PR0201MB2179.eurprd02.prod.outlook.com>

On Wed, Mar 22, 2017 at 05:59:49AM +0000, Amit Kama IL wrote:
> Add initial SX3000b platform related documentation to document tree:
>  - Vendor prefix
>  - Platform binding documentation
>  - Interrupt Controller Unit binding documentation.

Probably should be 3 patches. Preferred subject prefix is "dt-bindings: 
..."

> 
> Signed-off-by: Amit Kama <amit.kama@staixfy.com>
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/satixfy-icu.txt b/Documentation/devicetree/bindings/interrupt-controller/satixfy-icu.txt
> index 0000000..1893393
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/satixfy-icu.txt
> @@ -0,0 +1,47 @@
> +Satixfy SX3000B Interrupt Controller Unit (ICU)
> +
> +The ICU routes HW interrupts from the inter-module fabric to the
> +processor. For the MIPS interaptive, all interrupts are then routed

interaptive or interaptiv? I see both in the doc.


> +to the GIC.
> +
> +Required properties:
> +- compatible : Should be "satixfy,icu".

icu is fairly generic sounding. Should be satixfy,sx3000b-icu.

> +- reg - must be present and equal <0x1D4D0000 0x1C0>
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : Specifies the number of cells needed to encode an
> +  interrupt specifier.  Should be 1 - the GIC interrupt number
> +- interrupt-parent - Currently only the MIPS GIC is supported, so
> +<&gic> must be specified as parent
> +- interrupts : in interrupt parent form. For GIC it's
> +<GIC_SHARED x IRQ_TYPE_EDGE_RISING> where x is the interrupt number
> +allocated for ICU in GIC.
> +
> +
> +
> +
> +
> +Example:
> +
> +	icu: interrupt-controller@1d4d0000 {
> +		compatible = "sx,icu";
> +		reg = <0x1D4D0000 0x1C0>;

lowercase

> +
> +		interrupt-controller;
> +		#interrupt-cells = <1>;
> +
> +		interrupt-parent = <&gic>;
> +		interrupts = <GIC_SHARED 25 IRQ_TYPE_EDGE_RISING>;
> +	};
> +
> +	uart0: uart@1D4D09C0 {

serial@1d4d09c0

> +		compatible = "ns16550a";
> +		reg = <0x1D4D09C0 0x100>;

lowercase

> +
> +		interrupt-parent = <&icu>;
> +		interrupts = <3>;
> +
> +		clock-frequency = <270000000>;
> +
> +		reg-shift = <2>;
> +		reg-io-width = <4>;
> +	};
> diff --git a/Documentation/devicetree/bindings/mips/satixfy/sx3000b.txt b/Documentation/devicetree/bindings/mips/satixfy/sx3000b.txt
> index 0000000..7cae67b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mips/satixfy/sx3000b.txt
> @@ -0,0 +1,37 @@
> +Satixfy SX3000b SoC
> +=========================
> +
> +Required properties:
> +--------------------
> + - compatible: Must include "satixfy,sx3000".

The "b" in SX3000b is not significant?

> +
> +CPU nodes:
> +----------
> +A "cpus" node is required.  Required properties:
> + - #address-cells: Must be 1.
> + - #size-cells: Must be 0.
> +A CPU sub-node is also required for at least CPU 0.  Since the topology may
> +be probed via CPS, it is not necessary to specify secondary CPUs.  Required
> +properties:
> + - device_type: Must be "cpu".
> + - compatible: Must be "mti,interaptiv".
> + - reg: CPU number.
> + - clocks: Must include the CPU clock.  See ../../clock/clock-bindings.txt for
> +   details on clock bindings.
> +Example:
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		cpu@0 {
> +			device_type = "cpu";
> +			compatible = "mti,interaptiv";
> +			clocks	= <&ext>;
> +			reg = <0>;
> +		};
> +	};
> +
> +Interrupt controllers:
> +----------------------
> +Two nodes are required:
> + - mips,gic - MIPS Global Interrupt Controller - see Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt
> + - satixfy,icu - SX3000b SoC Interrupt Controller Unit - see Documentation/devicetree/bindings/interrupt-controller/satixfy-icu.txt
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index ec0bfb9..76819dd
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -261,6 +261,7 @@ rockchip	Fuzhou Rockchip Electronics Co., Ltd
>  samsung	Samsung Semiconductor
>  samtec	Samtec/Softing company
>  sandisk	Sandisk Corporation
> +satixfy Satixfy Technologies Ltd
>  sbs	Smart Battery System
>  schindler	Schindler
>  seagate	Seagate Technology PLC
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.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