Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH 03/11] ARM: shmobile: r8a7745: basic SoC support
From: Geert Uytterhoeven @ 2016-11-02  9:49 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Simon Horman, Linux-Renesas, Rob Herring, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Magnus Damm,
	Russell King,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
In-Reply-To: <1638480.5pJxF7pUnz-gHKXc3Y1Z8zGSmamagVegGFoWSdPRAKMAL8bYrjMMd8@public.gmane.org>

On Sat, Oct 29, 2016 at 12:16 AM, Sergei Shtylyov
<sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> wrote:
> Add minimal support for the RZ/G1E (R8A7745) SoC.
>
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

Reviewed-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
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 02/11] soc: renesas: rcar-sysc: add R8A7745 support
From: Geert Uytterhoeven @ 2016-11-02  9:48 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Simon Horman, Linux-Renesas, Rob Herring, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <5689104.8HluMoeKiR-gHKXc3Y1Z8zGSmamagVegGFoWSdPRAKMAL8bYrjMMd8@public.gmane.org>

On Sat, Oct 29, 2016 at 12:09 AM, Sergei Shtylyov
<sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> wrote:
> Add support for RZ/G1E (R8A7745) SoC power areas to the R-Car SYSC driver.
>
> Based on the original (and large) patch by Dmitry Shifrin
> <dmitry.shifrin-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>.
>
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

Reviewed-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
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 01/11] ARM: shmobile: r8a7745: add power domain index macros
From: Geert Uytterhoeven @ 2016-11-02  9:46 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Simon Horman, Linux-Renesas, Rob Herring, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Magnus Damm,
	Russell King,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
In-Reply-To: <1645729.DjklObBkNM-gHKXc3Y1Z8zGSmamagVegGFoWSdPRAKMAL8bYrjMMd8@public.gmane.org>

On Sat, Oct 29, 2016 at 12:07 AM, Sergei Shtylyov
<sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> wrote:
> Add macros usable by the device tree sources to reference R8A7745 SYSC power
> domains by index.
>
> Based on the original (and large) patch by Dmitry Shifrin
> <dmitry.shifrin-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>.
>
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

Reviewed-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/2] phy: qcom-qmp: new qmp phy driver for qcom-chipsets
From: Srinivas Kandagatla @ 2016-11-02  9:33 UTC (permalink / raw)
  To: Vivek Gautam
  Cc: kishon, robh+dt, Mark Rutland, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arm-msm
In-Reply-To: <CAFp+6iG=3QRU+Ffj+8xJaPrpy0p7TyjeX0khiOGQMtz-z-hiSg@mail.gmail.com>



On 02/11/16 07:26, Vivek Gautam wrote:
>>> +               phy_desc->tx = base + qphy->cfg->tx_offsets[id];
>>> >> +               phy_desc->rx = base + qphy->cfg->rx_offsets[id];
>>> >> +               phy_desc->pcs = base + qphy->cfg->pcs_offsets[id];
>>> >> +
>>> >> +               /*
>>> >> +                * Get PHY's Pipe clock, if any; USB3 and PCIe are PIPE
>>> >> +                * based phys, so they essentially have pipe clock
>>> >> +                */
>>> >> +               memset(&prop_name, 0, sizeof(prop_name));
>>> >> +               snprintf(prop_name, MAX_PROP_NAME, "pipe%d", id);
>>> >> +               phy_desc->pipe_clk = devm_clk_get(dev, prop_name);
>>> >> +               if (IS_ERR(phy_desc->pipe_clk)) {
>>> >> +                       if (qphy->cfg->type == PHY_TYPE_PCIE ||
>>> >> +                           qphy->cfg->type == PHY_TYPE_USB3) {
>>> >> +                               ret = PTR_ERR(phy_desc->pipe_clk);
>>> >> +                               if (ret != -EPROBE_DEFER)
>>> >> +                                       dev_err(dev,
>>> >> +                                       "failed to get lane%d pipe_clk\n",
>>> >> id);
>>> >> +                               return ret;
>>> >> +                       } else {
>>> >> +                               phy_desc->pipe_clk = NULL;
>>> >> +                       }
>>> >> +               }
>> >
>> >
>> > Do we need to really need phy type for this?
>> > You should proably make a flag in cfg to mark this rather then using phy
>> > type. Hopefully it will also simplify the logic.
> The pipe clock is something that's specific to PCIe and USB3 type
> phys (both are PIPE3 specs based phys). So i think it is okay
> to use the PHY_TYPE_{*} macros here. Looks a bit cleaner rather
> than having a cfg flag. No ?
Yes, it makes sense, I was not sure of full details of the pipe3 specs, 
now that you made it more clear.
Remember to add this in comments.

Thanks,
srini
>
> Using PHY_TYPE_{*} macros will also keep the doors open to
> other PHY types that are added at a later point in time.
>
>> >

^ permalink raw reply

* Re: [PATCH v2 34/37] docs: fix locations of several documents that got moved
From: Pavel Machek @ 2016-11-02  9:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Nicolas Pitre, Linus Walleij, Jaroslav Kysela, Chris Metcalf,
	Peter Loeffler, Finn Thain, Yaowei Bai, Jakub Wilk, linux-acpi,
	Geert Uytterhoeven, Guenter Roeck, Petr Mladek, Jean Delvare,
	linux-pm, Alexander Viro, Andy Lutomirski, Thomas Gleixner,
	Karsten Keil, Jiri Kosina, seokhoon.yoon, Li Zefan, Ryan Swan,
	Joe Perches, Andrew Morton, Mark
In-Reply-To: <20161019115918.1162d16e@vento.lan>


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

Hi!

> > Dunno, but kernel-parameters.txt was already quite long... for a file
> > that is referenced quite often. Adding admin-guide/ into the path does
> > not really help.
> 
> The big string name starts with Documentation/ :) There are some discussions 
> about changing it to doc/ (or docs/). Also, as you said, kernel-parameters
> is already a big name. Perhaps we could use, instead,
> > "kernel-parms".

cmdline?

> If we rename kernel-parameters.rst to kernel-parms.rst, plus the doc/ rename,
> then the string size will actually reduce:
> 
> -		(see Documentation/kernel-parameters.txt), the minimum possible
> +		(see doc/admin-guide/kernel-parms.rst), the minimum possible
> 
> > Maybe admin-guide should go directly into Documentation/ , as that's
> > what our users are interested in?
> 
> There are several problems if we keep them at Documentation/ dir:
> 
> - We'll end by mixing documents already converted to ReST with documents
>   not converted yet;
> 
> - A rename is needed anyway, as Sphinx only accepts ReST files that end
>   with the extension(s) defined at Documentation/conf.py (currently,
>   .rst);
> 
> - A partial documentation build is made by sub-directory. If we put
>   files under /Documentation, there's no way to build just one
>   book.

Well, documentation is primarily for users. I'm sure tools can adapt...

> > Plus, I'm not sure how many developers will figure out that process/
> > is what describes kernel patch submission process. We have processes
> > in the kernel, after all...
> 
> Do you have a better idea?

development/ ?

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

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

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply

* Re: [PATCH 1/2] phy: rockchip-inno-usb2: support otg-port for rk3399
From: kbuild test robot @ 2016-11-02  9:19 UTC (permalink / raw)
  Cc: kbuild-all, kishon, heiko, linux-kernel, linux-arm-kernel,
	linux-rockchip, devicetree, robh+dt, frank.wang, huangtao,
	dianders, briannorris, groeck, wulf
In-Reply-To: <1478072538-32081-2-git-send-email-wulf@rock-chips.com>

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

Hi William,

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on v4.9-rc3 next-20161028]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/William-Wu/support-USB2-PHY-OTG-port-for-rk3399/20161102-160006
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: i386-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> drivers/phy/phy-rockchip-inno-usb2.c:39:28: fatal error: linux/wakelock.h: No such file or directory
    #include <linux/wakelock.h>
                               ^
   compilation terminated.

vim +39 drivers/phy/phy-rockchip-inno-usb2.c

    33	#include <linux/platform_device.h>
    34	#include <linux/power_supply.h>
    35	#include <linux/regmap.h>
    36	#include <linux/mfd/syscon.h>
    37	#include <linux/usb/of.h>
    38	#include <linux/usb/otg.h>
  > 39	#include <linux/wakelock.h>
    40	
    41	#define BIT_WRITEABLE_SHIFT	16
    42	#define SCHEDULE_DELAY		(60 * HZ)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 56829 bytes --]

^ permalink raw reply

* [PATCH 2/2] pinctrl: tegra: Add driver to configure voltage and power of io pads
From: Laxman Dewangan @ 2016-11-02  9:09 UTC (permalink / raw)
  To: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	swarren-3lzwWm7+Weoh9ZMKESR00Q,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8
  Cc: jonathanh-DDmLM1+adcrQT0dZR+AlfA,
	yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Laxman Dewangan
In-Reply-To: <1478077742-25437-1-git-send-email-ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

NVIDIA Tegra124 and later SoCs support the multi-voltage level and
low power state of some of its IO pads. The IO pads can work in
the voltage of the 1.8V and 3.3V of IO power rail sources. When IO
interface are not used then IO pads can be configure in low power
state to reduce the power from that IO pads.

On Tegra124, the IO power rail source is auto detected by SoC and hence
it is only require to configure in low power mode if IO pads are not
used.

On T210 onwards, the auto-detection is removed from SoC and hence SW
must configure the PMC register explicitly to set proper voltage in
IO pads based on IO rail power source voltage.

This driver adds the IO pad driver to configure the power state and
IO pad voltage based on the usage and power tree via pincontrol
framework. The configuration can be static and dynamic.

Signed-off-by: Laxman Dewangan <ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

---
On top of the branch from Thierry's T186 work
	https://github.com/thierryreding/linux/tree/tegra186

 drivers/pinctrl/tegra/Kconfig                |  12 +
 drivers/pinctrl/tegra/Makefile               |   1 +
 drivers/pinctrl/tegra/pinctrl-tegra-io-pad.c | 369 +++++++++++++++++++++++++++
 3 files changed, 382 insertions(+)
 create mode 100644 drivers/pinctrl/tegra/pinctrl-tegra-io-pad.c

diff --git a/drivers/pinctrl/tegra/Kconfig b/drivers/pinctrl/tegra/Kconfig
index 24e20cc..eef1d6b 100644
--- a/drivers/pinctrl/tegra/Kconfig
+++ b/drivers/pinctrl/tegra/Kconfig
@@ -23,6 +23,18 @@ config PINCTRL_TEGRA210
 	bool
 	select PINCTRL_TEGRA
 
+config PINCTRL_TEGRA_IO_PAD
+	bool "Tegra IO pad Control Driver"
+	depends on ARCH_TEGRA
+	select PINCONF
+	select PINMUX
+	help
+	  NVIDIA Tegra124/210 SoC has IO pads which supports multi-voltage
+	  level of interfacing and deep power down mode of IO pads. The
+	  voltage of IO pads are SW configurable based on IO rail of that
+	  pads on T210. This driver provides the interface to change IO pad
+	  voltage and power state via pincontrol interface.
+
 config PINCTRL_TEGRA_XUSB
 	def_bool y if ARCH_TEGRA
 	select GENERIC_PHY
diff --git a/drivers/pinctrl/tegra/Makefile b/drivers/pinctrl/tegra/Makefile
index d9ea2be..3ebaaa2 100644
--- a/drivers/pinctrl/tegra/Makefile
+++ b/drivers/pinctrl/tegra/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_PINCTRL_TEGRA30)		+= pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_TEGRA114)		+= pinctrl-tegra114.o
 obj-$(CONFIG_PINCTRL_TEGRA124)		+= pinctrl-tegra124.o
 obj-$(CONFIG_PINCTRL_TEGRA210)		+= pinctrl-tegra210.o
+obj-$(CONFIG_PINCTRL_TEGRA_IO_PAD)	+= pinctrl-tegra-io-pad.o
 obj-$(CONFIG_PINCTRL_TEGRA_XUSB)	+= pinctrl-tegra-xusb.o
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra-io-pad.c b/drivers/pinctrl/tegra/pinctrl-tegra-io-pad.c
new file mode 100644
index 0000000..7af9552
--- /dev/null
+++ b/drivers/pinctrl/tegra/pinctrl-tegra-io-pad.c
@@ -0,0 +1,369 @@
+/*
+ * pinctrl-tegra-io-pad: IO PAD driver for configuration of IO rail and deep
+ *			 Power Down mode via pinctrl framework.
+ *
+ * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan-DDmLM1+adcrQT0dZR+AlfA@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.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <soc/tegra/pmc.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinctrl-utils.h"
+
+enum tegra_io_rail_pads_params {
+	TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE = PIN_CONFIG_END + 1,
+};
+
+static const struct pinconf_generic_params tegra_io_pads_cfg_params[] = {
+	{
+		.property = "nvidia,power-source-voltage",
+		.param = TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE,
+	},
+};
+
+struct tegra_io_pads_cfg_info {
+	const char *name;
+	const unsigned int pins[1];
+	enum tegra_io_pad pad_id;
+	bool voltage_can_change;
+	bool support_low_power_state;
+};
+
+struct tegra_io_pad_soc_data {
+	const struct tegra_io_pads_cfg_info *pads_cfg;
+	int num_pads_cfg;
+	const struct pinctrl_pin_desc *pins_desc;
+	int num_pins_desc;
+};
+
+struct tegra_io_pads_info {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+	const struct tegra_io_pad_soc_data *soc_data;
+};
+
+static int tegra_iop_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct tegra_io_pads_info *tiopi = pinctrl_dev_get_drvdata(pctldev);
+
+	return tiopi->soc_data->num_pads_cfg;
+}
+
+static const char *tegra_iop_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+						    unsigned int group)
+{
+	struct tegra_io_pads_info *tiopi = pinctrl_dev_get_drvdata(pctldev);
+
+	return tiopi->soc_data->pads_cfg[group].name;
+}
+
+static int tegra_iop_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+					    unsigned int group,
+					    const unsigned int **pins,
+					    unsigned int *num_pins)
+{
+	struct tegra_io_pads_info *tiopi = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = tiopi->soc_data->pads_cfg[group].pins;
+	*num_pins = 1;
+
+	return 0;
+}
+
+static const struct pinctrl_ops tegra_iop_pinctrl_ops = {
+	.get_groups_count	= tegra_iop_pinctrl_get_groups_count,
+	.get_group_name		= tegra_iop_pinctrl_get_group_name,
+	.get_group_pins		= tegra_iop_pinctrl_get_group_pins,
+	.dt_node_to_map		= pinconf_generic_dt_node_to_map_pin,
+	.dt_free_map		= pinctrl_utils_free_map,
+};
+
+static int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctldev,
+				    unsigned int pin, unsigned long *config)
+{
+	struct tegra_io_pads_info *tiopi = pinctrl_dev_get_drvdata(pctldev);
+	int param = pinconf_to_config_param(*config);
+	const struct tegra_io_pads_cfg_info *pad_cfg =
+					&tiopi->soc_data->pads_cfg[pin];
+	enum tegra_io_pad pad_id = pad_cfg->pad_id;
+	int arg = 0;
+	int ret;
+
+	switch (param) {
+	case TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE:
+		ret = tegra_io_pad_get_voltage(pad_id);
+		if (ret < 0)
+			return ret;
+		arg = ret;
+		break;
+
+	case PIN_CONFIG_LOW_POWER_MODE:
+		ret = tegra_io_pad_power_get_status(pad_id);
+		if (ret < 0)
+			return ret;
+		arg = !ret;
+		break;
+
+	default:
+		dev_err(tiopi->dev, "The parameter %d not supported\n", param);
+		return -EINVAL;
+	}
+
+	*config = pinconf_to_config_packed(param, (u16)arg);
+	return 0;
+}
+
+static int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctldev,
+				    unsigned int pin, unsigned long *configs,
+				    unsigned int num_configs)
+{
+	struct tegra_io_pads_info *tiopi = pinctrl_dev_get_drvdata(pctldev);
+	const struct tegra_io_pads_cfg_info *pad_cfg =
+					&tiopi->soc_data->pads_cfg[pin];
+	int pad_id = pad_cfg->pad_id;
+	u16 param_val;
+	int param;
+	int ret;
+	int i;
+
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		param_val = pinconf_to_config_argument(configs[i]);
+
+		switch (param) {
+		case TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE:
+			ret = tegra_io_pad_set_voltage(pad_id, param_val);
+			if (ret < 0) {
+				dev_err(tiopi->dev,
+					"Failed to set voltage %d of pin %u: %d\n",
+					param_val, pin, ret);
+				return ret;
+			}
+			break;
+
+		case PIN_CONFIG_LOW_POWER_MODE:
+			if (param_val)
+				ret = tegra_io_pad_power_disable(pad_id);
+			else
+				ret = tegra_io_pad_power_enable(pad_id);
+			if (ret < 0) {
+				dev_err(tiopi->dev,
+					"Failed to set DPD %d of pin %u: %d\n",
+					param_val, pin, ret);
+				return ret;
+			}
+			break;
+
+		default:
+			dev_err(tiopi->dev, "The parameter %d not supported\n",
+				param);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static const struct pinconf_ops tegra_io_pad_pinconf_ops = {
+	.pin_config_get = tegra_io_pad_pinconf_get,
+	.pin_config_set = tegra_io_pad_pinconf_set,
+};
+
+static struct pinctrl_desc tegra_iop_pinctrl_desc = {
+	.name = "pinctrl-tegra-io-pads",
+	.pctlops = &tegra_iop_pinctrl_ops,
+	.confops = &tegra_io_pad_pinconf_ops,
+	.custom_params = tegra_io_pads_cfg_params,
+	.num_custom_params = ARRAY_SIZE(tegra_io_pads_cfg_params),
+};
+
+static int tegra_iop_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct device_node *np_parent = pdev->dev.parent->of_node;
+	struct tegra_io_pads_info *tiopi;
+
+	if (!np_parent) {
+		dev_err(&pdev->dev, "PMC should be register from DT\n");
+		return -ENODEV;
+	}
+
+	tiopi = devm_kzalloc(&pdev->dev, sizeof(*tiopi), GFP_KERNEL);
+	if (!tiopi)
+		return -ENOMEM;
+
+	tiopi->dev = &pdev->dev;
+	pdev->dev.of_node = np_parent;
+	tiopi->soc_data = (const struct tegra_io_pad_soc_data *)id->driver_data;
+	tegra_iop_pinctrl_desc.pins = tiopi->soc_data->pins_desc;
+	tegra_iop_pinctrl_desc.npins = tiopi->soc_data->num_pins_desc;
+	platform_set_drvdata(pdev, tiopi);
+
+	tiopi->pctl = devm_pinctrl_register(dev, &tegra_iop_pinctrl_desc,
+					    tiopi);
+	if (IS_ERR(tiopi->pctl)) {
+		int ret = PTR_ERR(tiopi->pctl);
+
+		dev_err(dev, "Failed to register io-pad pinctrl driver: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+#define TEGRA124_PAD_INFO_TABLE(_entry_)			\
+	_entry_(0, "audio", AUDIO, true, false),		\
+	_entry_(1, "bb", BB, true, false),			\
+	_entry_(2, "cam", CAM, true, false),			\
+	_entry_(3, "comp", COMP, true, false),			\
+	_entry_(4, "csia", CSIA, true, false),			\
+	_entry_(5, "csib", CSIB, true, false),			\
+	_entry_(6, "csie", CSIE, true, false),			\
+	_entry_(7, "dsi", DSI, true, false),			\
+	_entry_(8, "dsib", DSIB, true, false),			\
+	_entry_(9, "dsic", DSIC, true, false),			\
+	_entry_(10, "dsid", DSID, true, false),			\
+	_entry_(11, "hdmi", HDMI, true, false),			\
+	_entry_(12, "hsic", HSIC, true, false),			\
+	_entry_(13, "hv", HV, true, false),			\
+	_entry_(14, "lvds", LVDS, true, false),			\
+	_entry_(15, "mipi-bias", MIPI_BIAS, true, false),	\
+	_entry_(16, "nand", NAND, true, false),			\
+	_entry_(17, "pex-bias", PEX_BIAS, true, false),		\
+	_entry_(18, "pex-clk1", PEX_CLK1, true, false),		\
+	_entry_(19, "pex-clk2", PEX_CLK2, true, false),		\
+	_entry_(20, "pex-ctrl", PEX_CNTRL, true, false),	\
+	_entry_(21, "sdmmc1", SDMMC1, true, false),		\
+	_entry_(22, "sdmmc3", SDMMC3, true, false),		\
+	_entry_(23, "sdmmc4", SDMMC4, true, false),		\
+	_entry_(24, "sys-ddc", SYS_DDC, true, false),		\
+	_entry_(25, "uart", UART, true, false),			\
+	_entry_(26, "usb0", USB0, true, false),			\
+	_entry_(27, "usb1", USB1, true, false),			\
+	_entry_(28, "usb2", USB2, true, false),			\
+	_entry_(29, "usb-bias", USB_BIAS, true, false)
+
+#define TEGRA210_PAD_INFO_TABLE(_entry_)			\
+	_entry_(0, "audio", AUDIO, true, true),			\
+	_entry_(1, "audio-hv", AUDIO_HV, true, true),		\
+	_entry_(2, "cam", CAM, true, true),			\
+	_entry_(3, "csia", CSIA, true, false),			\
+	_entry_(4, "csib", CSIB, true, false),			\
+	_entry_(5, "csic", CSIC, true, false),			\
+	_entry_(6, "csid", CSID, true, false),			\
+	_entry_(7, "csie", CSIE, true, false),			\
+	_entry_(8, "csif", CSIF, true, false),			\
+	_entry_(9, "dbg", DBG, true, true),			\
+	_entry_(10, "debug-nonao", DEBUG_NONAO, true, false),	\
+	_entry_(11, "dmic", DMIC, true, true),			\
+	_entry_(12, "dp", DP, true, false),			\
+	_entry_(13, "dsi", DSI, true, false),			\
+	_entry_(14, "dsib", DSIB, true, false),			\
+	_entry_(15, "dsic", DSIC, true, false),			\
+	_entry_(16, "dsid", DSID, true, false),			\
+	_entry_(17, "emmc", SDMMC4, true, false),		\
+	_entry_(18, "emmc2", EMMC2, true, false),		\
+	_entry_(19, "gpio", GPIO, true, true),			\
+	_entry_(20, "hdmi", HDMI, true, false),			\
+	_entry_(21, "hsic", HSIC, true, false),			\
+	_entry_(22, "lvds", LVDS, true, false),			\
+	_entry_(23, "mipi-bias", MIPI_BIAS, true, false),	\
+	_entry_(24, "pex-bias", PEX_BIAS, true, false),		\
+	_entry_(25, "pex-clk1", PEX_CLK1, true, false),		\
+	_entry_(26, "pex-clk2", PEX_CLK2, true, false),		\
+	_entry_(27, "pex-ctrl", PEX_CNTRL, false, true),	\
+	_entry_(28, "sdmmc1", SDMMC1, true, true),		\
+	_entry_(29, "sdmmc3", SDMMC3, true, true),		\
+	_entry_(30, "spi", SPI, true, true),			\
+	_entry_(31, "spi-hv", SPI_HV, true, true),		\
+	_entry_(32, "uart", UART, true, true),			\
+	_entry_(33, "usb0", USB0, true, false),			\
+	_entry_(34, "usb1", USB1, true, false),			\
+	_entry_(35, "usb2", USB2, true, false),			\
+	_entry_(36, "usb3", USB3, true, false),			\
+	_entry_(37, "usb-bias", USB_BIAS, true, false)
+
+#define TEGRA_IO_PAD_INFO(_id, _name, _pad_id, _lpstate, _vchange)	\
+	{								\
+		.name = _name,						\
+		.pins = {(_id)},					\
+		.pad_id = TEGRA_IO_PAD_##_pad_id,			\
+		.voltage_can_change = (_vchange),			\
+		.support_low_power_state = (_lpstate),			\
+	}
+
+static const struct tegra_io_pads_cfg_info tegra124_io_pads_cfg_info[] = {
+	TEGRA124_PAD_INFO_TABLE(TEGRA_IO_PAD_INFO),
+};
+
+static const struct tegra_io_pads_cfg_info tegra210_io_pads_cfg_info[] = {
+	TEGRA210_PAD_INFO_TABLE(TEGRA_IO_PAD_INFO),
+};
+
+#define TEGRA_IO_PAD_DESC(_id, _name, _pad_id,  _vchange, _lpstate)	\
+	PINCTRL_PIN(_id, _name)
+
+static const struct pinctrl_pin_desc tegra124_io_pads_pinctrl_desc[] = {
+	TEGRA124_PAD_INFO_TABLE(TEGRA_IO_PAD_DESC),
+};
+
+static const struct pinctrl_pin_desc tegra210_io_pads_pinctrl_desc[] = {
+	TEGRA210_PAD_INFO_TABLE(TEGRA_IO_PAD_DESC),
+};
+
+static const struct tegra_io_pad_soc_data tegra124_io_pad_soc_data = {
+	.pins_desc	= tegra124_io_pads_pinctrl_desc,
+	.num_pins_desc	= ARRAY_SIZE(tegra124_io_pads_pinctrl_desc),
+	.pads_cfg	= tegra124_io_pads_cfg_info,
+	.num_pins_desc	= ARRAY_SIZE(tegra124_io_pads_cfg_info),
+};
+
+static const struct tegra_io_pad_soc_data tegra210_io_pad_soc_data = {
+	.pins_desc	= tegra210_io_pads_pinctrl_desc,
+	.num_pins_desc	= ARRAY_SIZE(tegra210_io_pads_pinctrl_desc),
+	.pads_cfg	= tegra210_io_pads_cfg_info,
+	.num_pins_desc	= ARRAY_SIZE(tegra210_io_pads_cfg_info),
+};
+
+static const struct platform_device_id tegra_io_pads_dev_id[] = {
+	{
+		.name = "pinctrl-t124-io-pad",
+		.driver_data = (kernel_ulong_t)&tegra124_io_pad_soc_data,
+	}, {
+		.name = "pinctrl-t210-io-pad",
+		.driver_data = (kernel_ulong_t)&tegra210_io_pad_soc_data,
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(platform, tegra_io_pads_dev_id);
+
+static struct platform_driver tegra_iop_pinctrl_driver = {
+	.driver		= {
+		.name	= "pinctrl-tegra-io-pad",
+	},
+	.probe		= tegra_iop_pinctrl_probe,
+	.id_table	= tegra_io_pads_dev_id,
+};
+
+module_platform_driver(tegra_iop_pinctrl_driver);
+
+MODULE_DESCRIPTION("NVIDIA TEGRA IO pad Control Driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
-- 
2.1.4

^ permalink raw reply related

* [PATCH 1/2] pinctrl: tegra: Add DT binding for io pads control
From: Laxman Dewangan @ 2016-11-02  9:09 UTC (permalink / raw)
  To: thierry.reding, swarren, linus.walleij, robh+dt, mark.rutland
  Cc: jonathanh, yamada.masahiro, linux-gpio, devicetree, linux-tegra,
	linux-kernel, Laxman Dewangan
In-Reply-To: <1478077742-25437-1-git-send-email-ldewangan@nvidia.com>

NVIDIA Tegra124 and later SoCs support the multi-voltage level and
low power state of some of its IO pads. The IO pads can work in
the voltage of the 1.8V and 3.3V of IO power rail sources. When IO
interface are not used then IO pads can be configure in low power
state to reduce the power from that IO pads.

On Tegra124, the IO power rail source is auto detected by SoC and hence
it is only require to configure in low power mode if IO pads are not
used.

On T210 onwards, the auto-detection is removed from SoC and hence SW
must configure the PMC register explicitly to set proper voltage in
IO pads based on IO rail power source voltage.

Add DT binding document for detailing the DT properties for
configuring IO pads voltage levels and its power state.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
On top of the branch from Thierry's T186 work
	https://github.com/thierryreding/linux/tree/tegra186

 .../bindings/pinctrl/nvidia,tegra-io-pad.txt       | 112 +++++++++++++++++++++
 include/dt-bindings/pinctrl/pinctrl-tegra-io-pad.h |  21 ++++
 2 files changed, 133 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra-io-pad.txt
 create mode 100644 include/dt-bindings/pinctrl/pinctrl-tegra-io-pad.h

diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra-io-pad.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra-io-pad.txt
new file mode 100644
index 0000000..15cd21c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra-io-pad.txt
@@ -0,0 +1,112 @@
+NVIDIA Tegra PMC IO pad controller
+
+NVIDIA Tegra124 and later SoCs support the multi-voltage level and
+low power state of some of its IO pads. The IO pads can work in
+the voltage of the 1.8V and 3.3V of IO power rail sources. When IO
+interface are not used then IO pads can be configure in low power
+state to reduce the power from that IO pads.
+
+On Tegra124, the IO power rail source is auto detected by SoC and hence
+it is only require to configure in low power mode if IO pads are not
+used.
+
+On T210 onwards, the auto-detection is removed from SoC and hence SW
+must configure the PMC register explicitly to set proper voltage in
+IO pads based on IO rail power source voltage.
+
+The voltage configurations and low power state of IO pads should be done
+in boot if it is not going to change other wise dynamically based on IO
+rail voltage on that IO pads and usage of IO pads
+
+The DT property of the io pads must be under the node of pmc i.e.
+pmc@7000e400 for Tegra124 onwards.
+
+Please refer to <pinctrl-bindings.txt> in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Tegra's pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for an
+IO pads, or a list of IO pads. This configuration can include the voltage and
+power enable/disable control
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content. Each subnode only affects those
+parameters that are explicitly listed. Unspecified is represented as an absent
+property,
+
+See the TRM to determine which properties and values apply to each IO pads.
+Macro values for property values are defined in
+<dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
+
+The voltage supported on the pads are 1.8V and 3.3V. The enums are defined as:
+	For 1.8V, use TEGRA_IO_PAD_POWER_SOURCE_1800000UV
+	For 3.3V, use TEGRA_IO_PAD_POWER_SOURCE_3300000UV
+
+Required subnode-properties:
+==========================
+- pins : An array of strings. Each string contains the name of an IO pads. Valid
+	 values for these names are listed below.
+
+Optional subnode-properties:
+==========================
+-nvidia,power-source-voltage:	Integer. The voltage level of IO pads. The
+				valid values are 1.8V and 3.3V. Macros are
+				defined for these voltage levels in
+				<dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
+				Use TEGRA_IO_PAD_POWER_SOURCE_1800000UV for 1.8V
+				Use TEGRA_IO_PAD_POWER_SOURCE_3300000UV for 3.3V
+
+				All IO pads do not support the 1.8V/3.3V
+				configurations. Valid values for "pins" are
+				audio-hv, dmic, gpio, sdmmc1, sdmmc3, spi-hv.
+
+Other than above, following properties are supported from generic pin
+configuration explained in <dt-bindings/pinctrl/pinctrl-binding.txt>.
+low-power-enable:		enable low power mode.
+low-power-disable:		disable low power mode.
+
+Valid values for pin for T124 are:
+	audio, bb, cam, comp, csia, csib, csie, dsi, dsib, dsic, dsid, hdmi,
+	hsic, hv, lvds, mipi-bias, nand, pex-bias, pex-clk1, pex-clk2,
+	pex-ctrl, sdmmc1, sdmmc3, sdmmc4, sys-ddc, uart, usb0, usb1, usb2,
+	usb-bias
+
+	All above pins support low power mode.
+
+Valid values for pin for T210 are:
+	audio, audio-hv, cam, csia, csib, csic, csid, csie, csif,
+	dbg, debug-nonao, dmic, dp, dsi, dsib, dsic, dsid, emmc, emmc2,
+	gpio, hdmi, hsic, lvds, mipi-bias, pex-bias, pex-clk1, pex-clk2,
+	pex-ctrl, sdmmc1, sdmmc3, spi, spi-hv, uart, usb-bias, usb0,
+	usb1, usb2, usb3.
+
+	All above pins support low power mode. However, all IO pads do not
+	support the 1.8V/3.3V configurations. Valid values for
+	nvidia,io-pad-voltage are:
+		audio, audio-hv, cam, dbg, dmic, gpio, pex-ctrl, sdmmc1, sdmmc3,
+		spi, spi-hv,uart
+
+Example:
+	#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
+	pmc@7000e400 {
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&tegra_io_pad_volt_default>;
+		tegra_io_pad_volt_default: common {
+			audio-hv {
+				pins = "audio-hv";
+				nvidia,power-source-voltage = <TEGRA_IO_PAD_POWER_SOURCE_3300000UV>;
+			};
+
+			gpio {
+				pins = "gpio";
+				invidia,power-source-voltage = <TEGRA_IO_PAD_POWER_SOURCE_1800000UV>;
+			};
+
+			audio {
+				pins = "audio", "dmic", "sdmmc1", "sdmmc3";
+				low-power-enable;
+			};
+		};
+	};
diff --git a/include/dt-bindings/pinctrl/pinctrl-tegra-io-pad.h b/include/dt-bindings/pinctrl/pinctrl-tegra-io-pad.h
new file mode 100644
index 0000000..ae55768
--- /dev/null
+++ b/include/dt-bindings/pinctrl/pinctrl-tegra-io-pad.h
@@ -0,0 +1,21 @@
+/*
+ * pinctrl-tegra-io-pad.h: Provides constants for Tegra IO pads
+ *			   pinctrl bindings.
+ *
+ * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_TEGRA_IO_PAD_H
+#define _DT_BINDINGS_PINCTRL_TEGRA_IO_PAD_H
+
+/* Power source voltage of IO pads. */
+#define TEGRA_IO_PAD_POWER_SOURCE_1800000UV	0
+#define TEGRA_IO_PAD_POWER_SOURCE_3300000UV	1
+
+#endif
-- 
2.1.4

^ permalink raw reply related

* [PATCH 0/2] pinctrl: tegra: Add support for IO pad control
From: Laxman Dewangan @ 2016-11-02  9:09 UTC (permalink / raw)
  To: thierry.reding, swarren, linus.walleij, robh+dt, mark.rutland
  Cc: jonathanh, yamada.masahiro, linux-gpio, devicetree, linux-tegra,
	linux-kernel, Laxman Dewangan

NVIDIA Tegra124 and later SoCs support the multi-voltage level and
low power state of some of its IO pads. The IO pads can work in
the voltage of the 1.8V and 3.3V of IO power rail sources. When IO
interface are not used then IO pads can be configure in low power
state to reduce the power from that IO pads.

This series add the support of configuration of IO pad via pinctrl
framework. The io pad driver uses the tegra PMC interface.

---
This driver was sent earlier for review along with soc/tegra pmc
changes. During review, decided to first conclude in soc/tegra pmc
patches and then review this.
    
Thierry applied the pmc patches in the private tree
        https://github.com/thierryreding/linux/tree/tegra186
and he wanted to have the patches for user of the new APIs so that
it can be pushed to mainline.
    
Sending the pinctrl driver. This needs Ack/reviewed from pinctrl subsystem
i.e. Linus Welleij to apply in the Thierry's T186 branch along with
PMC patches.

Laxman Dewangan (2):
  pinctrl: tegra: Add DT binding for io pads control
  pinctrl: tegra: Add driver to configure voltage and power of io pads

 .../bindings/pinctrl/nvidia,tegra-io-pad.txt       | 112 +++++++
 drivers/pinctrl/tegra/Kconfig                      |  12 +
 drivers/pinctrl/tegra/Makefile                     |   1 +
 drivers/pinctrl/tegra/pinctrl-tegra-io-pad.c       | 369 +++++++++++++++++++++
 include/dt-bindings/pinctrl/pinctrl-tegra-io-pad.h |  21 ++
 5 files changed, 515 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra-io-pad.txt
 create mode 100644 drivers/pinctrl/tegra/pinctrl-tegra-io-pad.c
 create mode 100644 include/dt-bindings/pinctrl/pinctrl-tegra-io-pad.h

-- 
2.1.4

^ permalink raw reply

* Re: [PATCH v4 00/23] soc: renesas: Add R-Car RST driver for obtaining mode pin state
From: Geert Uytterhoeven @ 2016-11-02  9:02 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Michael Turquette, Arnd Bergmann, Olof Johansson, Kevin Hilman,
	Philipp Zabel, Magnus Damm,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux-Renesas,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Simon Horman
In-Reply-To: <20161031232537.GT16026-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

Hi Stephen,

Thanks for your answers!

On Tue, Nov 1, 2016 at 12:25 AM, Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org> wrote:
> On 10/31, Geert Uytterhoeven wrote:
>> Hi Mike, Stephen, Arnd, Olof, Kevin,
>>
>> Is the merge strategy [see ##### below] OK for you?
>> Thanks a lot!
>>
>> On Mon, Oct 31, 2016 at 9:19 AM, Simon Horman <horms-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org> wrote:
>> > On Wed, Oct 26, 2016 at 02:00:24PM +0200, Geert Uytterhoeven wrote:
>> >> On Fri, Oct 21, 2016 at 3:17 PM, Geert Uytterhoeven
>> >> <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org> wrote:
>> >> > Currently the R-Car Clock Pulse Generator (CPG) drivers obtains the
>> >> > state of the mode pins either by a call from the platform code, or
>> >> > directly by using a hardcoded register access. This is a bit messy, and
>> >> > creates a dependency between driver and platform code.
>> >> >
>> >> > This patch series converts the various Renesas R-Car clock drivers
>> >> > and support code from reading the mode pin states using a hardcoded
>> >> > register access to using a new minimalistic R-Car RST driver.
>> >> >
>> >> > All R-Car clock drivers will rely on the presence in DT of a device node
>> >> > for the RST module.  Backwards compatibility with old DTBs is retained
>> >> > only for R-Car Gen2, which has fallback code using its own private copy
>> >> > of rcar_gen2_read_mode_pins().
>> >> >
>> >> > After this, there is still one remaining user of
>> >> > rcar_gen2_read_mode_pins() left in platform code. A patch series to
>> >> > remove that user has already been posted, though ("[PATCH/RFT 0/4] ARM:
>> >> > shmobile: R-Car Gen2: Allow booting secondary CPU cores in debug mode").
>> >> > Since v3, the other user has been removed in commit 9f5ce39ddb8f68b3
>> >> > ("ARM: shmobile: rcar-gen2: Obtain extal frequency from DT").
>> >> >
>> >> > This series consists of 5 parts:
>> >> >   A. Patches 1 and 2 add DT bindings and driver code for the R-Car RST
>> >> >      driver,
>> >> >   B. Patches 3-11 add device nodes for the RST modules to the R-Car DTS
>> >> >      files,
>> >> >   C. Patches 12-17 convert the clock drivers to call into the new R-Car
>> >> >      RST driver,
>> >> >   D. Patches 18-20 remove passing mode pin state to the clock drivers
>> >> >      from the platform code,
>> >> >   E. Patches 21-23 remove dead code from the clock drivers.
>> >> >
>> >> > As is usually the case with moving functionality from platform code to
>> >> > DT, there are lots of hard dependencies:
>> >> >   - The DT updates in Part B can be merged as soon as the DT bindings in
>> >> >     Part A have been approved,
>> >> >   - The clock driver updates in Part C depend functionally on the driver
>> >> >     code in Part A, and on the DT updates in Part B,
>> >> >   - The board code cleanups in Part D depend on the clock driver updates
>> >> >     in Part C,
>> >> >   - The block driver cleanups in part E depend on the board code
>> >> >     cleanups in part D.
>> >> >
>> >> > Hence to maintain the required lockstep between SoC driver, clock
>> >> > drivers, shmobile platform code, and shmobile DT, I propose to queue up
>> >> > all patches in a single branch against v4.9-rc1, and send pull requests
>> >> > to both Mike/Stephen (clock) and Simon (rest).
>> >> >
>> >> > ***
>> >>
>> >> >   - Mike/Stephen/Simon/Magnus: Are you OK with the suggested merge
>> >> >     approach above?
>> >>
>> >> Is this OK for you?
>>
>> #####
>>
>> (link to the full series at
>>  https://groups.google.com/forum/#!topic/linux.kernel/fLSFsjOgPT8)
>
> Would the pull requests for clk also have dts changes at the base
> of the tree? Perhaps clk side can just ack the clk patches and

Yes they would: this is moving functionality from platform code to DT.
Without the DT updates, it will break bisection (except for R-Car Gen2,
where we have fallback code to handle old DTBs).

> then have it all routed through arm-soc? The only worry I have is
> if we need to make some sort of change in clk side that conflicts
> with these changes. I don't usually like taking dts changes
> through clk tree, so I'd like to avoid that if possible.

Everything could go through arm-soc only with your Acked-by.
However, there are new clock drivers pending on this series.
Either they have to go through arm-soc, too, or this series would
be pulled into the clk tree with these new clock drivers.

> Part E could happen anytime after everything else happens, so
> that doesn't seem like a concern.

Part E can indeed by postponed.
But if parts A-D are applied together, there's no reason to postpone part E.

> Part C could also be made to
> only call into the new reset drivers if the reset dts nodes are
> present? If that's done then we could merge clk patches anytime
> and remove the dead code and the node search at some later time
> when everything has settled?

That would require adding more backwards compatibility code for
old DTBs, even for platform where we're not interested in maintaining
that. In addition, Part C depends on the header file for the reset driver
to compile the clock driver, even if you would add some DT detection,
and on the reset driver to link. So I'm afraid this is not feasible.

Thanks again!

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* RE: [RFC 5/5] doc_rst: media: New SDR formats SC16, SC18 & SC20
From: Ramesh Shanmugasundaram @ 2016-11-02  9:00 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	mchehab-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org,
	sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org,
	crope-X3B1VOXEql0@public.gmane.org, Chris Paterson,
	geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org,
	linux-media-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <2893157.XL3Txm4q5I@avalon>

Hi Laurent,

Any further thoughts on the SDR format please (especially the comment below). I would appreciate your feedback.

> > On Wednesday 12 Oct 2016 15:10:29 Ramesh Shanmugasundaram wrote:
> > > This patch adds documentation for the three new SDR formats
> > >
> > > V4L2_SDR_FMT_SCU16BE
> > > V4L2_SDR_FMT_SCU18BE
> > > V4L2_SDR_FMT_SCU20BE
[snip]
> > > +
> > > +       -  start + 0:
> > > +
> > > +       -  I'\ :sub:`0[D13:D6]`
> > > +
> > > +       -  I'\ :sub:`0[D5:D0]`
> > > +
> > > +    -  .. row 2
> > > +
> > > +       -  start + buffer_size/2:
> > > +
> > > +       -  Q'\ :sub:`0[D13:D6]`
> > > +
> > > +       -  Q'\ :sub:`0[D5:D0]`
> >
> > The format looks planar, does it use one V4L2 plane (as does NV12) or
> > two
> > V4L2 planes (as does NV12M) ? Same question for the other formats.
> 
> Thank you for bringing up this topic. This is one of the key design
> dilemma.
> 
> The I & Q data for these three SDR formats comes from two different DMA
> channels and hence two separate pointers -> we could say it is v4l2 multi-
> planar. Right now, I am making it look like a single plane by presenting
> the data in one single buffer ptr.
> 
> For e.g. multi-planar SC16 format would look something like this
> 
> <------------------------32bits---------------------->
> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 0
> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 4 ...
> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 0
> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 4
> 
> My concerns are
> 
> 1) These formats are not a standard as the video "Image Formats". These
> formats are possible when we use DRIF + MAX2175 combination. If we
> interface with a different tuner vendor, the above format(s) MAY/MAY NOT
> be re-usable. We do not know at this point. This is the main open item for
> discussion in the cover letter.
> 
> 2) MPLANE support within V4L2 seems specific to video. Please correct me
> if this is wrong interpretation.
> 	- struct v4l2_format contains v4l2_sdr_format and
> v4l2_pix_format_mplane as members of union. Should I create a new
> v4l2_sdr_format_mplane? If I have to use v4l2_pix_format_mplane most of
> the video specific members would be unused (it would be similar to using
> v4l2_pix_format itself instead of v4l2_sdr_format)?
> 
> 	- The above decision (accomodate SDR & MPLANE) needs to be
> propagated across the framework. Is this the preferred approach?
> 
> It goes back to point (1). As of today, the change set for this combo
> (DRIF+MAX2175) introduces new SDR formats only. Should it add further
> SDR+MPLANE support to the framework as well?
> 
> I would appreciate your suggestions on this regard.
> 

Thanks,
Ramesh
--
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 1/2] phy: qcom-qusb2: New driver for QUSB2 PHY on Qcom chips
From: Vivek Gautam @ 2016-11-02  8:59 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: robh+dt, Mark Rutland, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arm-msm
In-Reply-To: <12a93817-0d3c-b35c-2e02-91f8ed2ee2a6@ti.com>

Hi Kishon,


On Thu, Oct 27, 2016 at 1:26 AM, Kishon Vijay Abraham I <kishon@ti.com> wrote:
> Hi,

I am currently on vacation, so the responses are delayed a bit.
Please bear with me.

>
> On Wednesday 19 October 2016 04:13 PM, Vivek Gautam wrote:
>> PHY transceiver driver for QUSB2 phy controller that provides
>> HighSpeed functionality for DWC3 controller present on
>> Qualcomm chipsets.
>>
>> This driver is based on phy-msm-qusb driver available in
>> msm-4.4 kernel @codeaurora[1]
>>
>> [1] https://source.codeaurora.org/quic/la/kernel/msm-4.4/log/?h=caf/3.18/msm-3.18
>
> I'd prefer only LKML links in commit msg. This can be part of the comment
> section below ---.

Sure, will use LKML links only.

>>
>> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
>> Cc: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>  .../devicetree/bindings/phy/qcom-qusb2-phy.txt     |  37 ++
>>  drivers/phy/Kconfig                                |  10 +
>>  drivers/phy/Makefile                               |   1 +
>>  drivers/phy/phy-qcom-qusb2.c                       | 577 +++++++++++++++++++++
>>  4 files changed, 625 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>>  create mode 100644 drivers/phy/phy-qcom-qusb2.c

[snip]

>> +struct qusb2_phy_init_tbl {
>> +     unsigned int reg_offset;
>> +     unsigned int cfg_val;
>> +};
>> +#define QCOM_QUSB2_PHY_INIT_CFG(reg, val) \
>> +     {                               \
>> +             .reg_offset = reg,      \
>> +             .cfg_val = val,         \
>> +     }
>> +
>> +static struct qusb2_phy_init_tbl msm8996_phy_init_tbl[] = {
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xF8),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xB3),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xC0),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9F),
>> +     QCOM_QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
>> +};
> we should generalize this so that it could be used for any phys. All these
> tuning parameters can come from dt.
>
> phy,tx-swing = <reg_offset> <swing value>;
> phy,rx-swing = <reg_offset> <swing value>;
> phy,tx-compensation = <reg_offset> <swing value>;
> phy,rx-compensation = <reg_offset> <swing value>;
> ..
>
> We have to identify all the calibration parameters and add a dt property for
> each parameter. The phy-core can just use these properties to calibrate or tune
> the PHY.

Yes, that will make life easier.

Things look simpler with this qusb2 phy driver.
But, same is not the case with the qmp-phy driver
that supports few other phys on msm chipsets.
That qmp phy driver has a list of ~100 odd registers that
need to be programmed during initialization.
We, then, don't need to touch those settings any time later.
The settings include, the common PLL settings, tx, rx and the
pcs settings.

I will take a look at these drivers once again, and see if we can group
the settings and make few generic bindings that can be utilized
but the phy drivers in general.

>
>> +
>> +struct qusb2_phy_init_cfg {
>> +     struct qusb2_phy_init_tbl *phy_init_tbl;
>> +     int phy_init_tbl_sz;
>> +};
>> +
>> +const struct qusb2_phy_init_cfg msm8996_phy_init_cfg = {
>> +     .phy_init_tbl = msm8996_phy_init_tbl,
>> +     .phy_init_tbl_sz = ARRAY_SIZE(msm8996_phy_init_tbl),
>> +};
>> +
>> +/**
>> + * struct qusb2_phy: Structure holding qusb2 phy attributes.
>> + *
>> + * @phy: pointer to generic phy.
>> + * @base: pointer to iomapped memory space for qubs2 phy.
>> + *
>> + * @cfg_ahb_clk: pointer to AHB2PHY interface clock.
>> + * @ref_clk: pointer to reference clock.
>> + * @ref_clk_src: pointer to source to reference clock.
>> + * @iface_src: pointer to phy interface clock.
>> + * @clk_enabled: check if clocks are enabled.
>
> Why is this needed? IMO this should not be used. clk framework can handle this
> better since it maintains a reference count for clk_enable/clk_disable.

Ok, will remove this.

>> + *
>> + * @phy_reset: Pointer to phy reset control
>> + *
>> + * @vdda_phy: vdd supply to the phy core block.
>> + * @vdda_pll: 1.8V vdd supply to ref_clk block.
>> + * @vdda_phy_dpdm: 3.1V vdd supply to Dp/Dm port signals.
>> + * @pwr_enabled: check if the regulators are enabled.
>
> same here.

will remove this as well.

>> + * @tcsr: pointer to TCSR syscon register map.
>> + * @clk_scheme_offset: offset to PHY_CLK_SCHEME register in TCSR map.
>> + * @cfg: phy initialization config data
>> + */
>> +struct qusb2_phy {
>> +     struct phy *phy;
>> +     void __iomem *base;
>> +
>> +     struct clk *cfg_ahb_clk;
>> +     struct clk *ref_clk;
>> +     struct clk *ref_clk_src;
>> +     struct clk *iface_clk;
>> +     bool clk_enabled;
>> +
>> +     struct reset_control *phy_reset;
>> +
>> +     struct regulator *vdd_phy;
>> +     struct regulator *vdda_pll;
>> +     struct regulator *vdda_phy_dpdm;
>> +     bool pwr_enabled;
>> +
>> +     struct regmap *tcsr;
>> +     unsigned int clk_scheme_offset;
>> +
>> +     const struct qusb2_phy_init_cfg *cfg;
>> +};
>> +
>> +static inline void qusb2_set_bits(void __iomem *reg, u32 mask)
>
> mask is misleading. just use val.

Ok, will modify this.

>> +{
>> +     u32 val;
>> +
>> +     val = readl_relaxed(reg);
>> +     val |= mask;
>> +     writel_relaxed(val, reg);
>> +
>> +     /* Ensure above write is completed */
>> +     mb();
>> +}
>> +
>> +static inline void qusb2_clr_bits(void __iomem *reg, u32 mask)
>> +{
>> +     u32 val;
>> +
>> +     val = readl_relaxed(reg);
>> +     val &= ~mask;
>> +     writel_relaxed(val, reg);
>> +
>> +     /* Ensure above write is completed */
>> +     mb();
>> +}
>> +
>> +static void qcom_qusb2_phy_configure(void __iomem *base,
>> +                             struct qusb2_phy_init_tbl init_tbl[],
>> +                             int init_tbl_sz)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < init_tbl_sz; i++) {
>> +             writel_relaxed(init_tbl[i].cfg_val,
>> +                             base + init_tbl[i].reg_offset);
>> +     }
>> +
>> +     /* flush buffered writes */
>> +     mb();
>> +}
>> +
>> +static void qusb2_phy_enable_clocks(struct qusb2_phy *qphy, bool on)
>> +{
>> +     dev_dbg(&qphy->phy->dev, "%s(): clocks_enabled:%d on:%d\n",
>> +                     __func__, qphy->clk_enabled, on);
>
> unnecessary debug print IMO, given that there is another debug print before the
> function returns.

Will remove this.

>> +
>> +     if (!qphy->clk_enabled && on) {
>> +             clk_prepare_enable(qphy->cfg_ahb_clk);
>> +             if (qphy->iface_clk)
>> +                     clk_prepare_enable(qphy->iface_clk);
>> +             clk_prepare_enable(qphy->ref_clk_src);
>> +             qphy->clk_enabled = true;
>> +     }
>> +
>> +     if (qphy->clk_enabled && !on) {
>> +             clk_disable_unprepare(qphy->ref_clk_src);
>> +             if (qphy->iface_clk)
>> +                     clk_disable_unprepare(qphy->iface_clk);
>> +             clk_disable_unprepare(qphy->cfg_ahb_clk);
>> +             qphy->clk_enabled = false;
>> +     }
>> +
>> +     dev_dbg(&qphy->phy->dev, "%s(): clocks_enabled:%d\n", __func__,
>> +                                             qphy->clk_enabled);
>
> even this should be dev_vdbg.

Ok, will use dev_vdbg.

>> +}
>> +
>> +static int qusb2_phy_enable_power(struct qusb2_phy *qphy, bool on)
>> +{
>> +     int ret = 0;
>> +     struct device *dev = &qphy->phy->dev;
>> +
>> +     dev_dbg(dev, "%s(): turn %s regulators. power_enabled:%d\n",
>> +                     __func__, on ? "on" : "off", qphy->pwr_enabled);
>> +
>> +     if (qphy->pwr_enabled == on)
>> +             return 0;
>> +
>> +     if (!on)
>> +             goto disable_vdda_phy_dpdm;
>> +
>> +     ret = regulator_enable(qphy->vdd_phy);
>> +     if (ret) {
>> +             dev_err(dev, "Unable to enable vdd-phy:%d\n", ret);
>> +             goto err_vdd_phy;
>> +     }
>> +
>> +     ret = regulator_enable(qphy->vdda_pll);
>> +     if (ret) {
>> +             dev_err(dev, "Unable to enable vdda-pll:%d\n", ret);
>> +             goto disable_vdd_phy;
>> +     }
>> +
>> +     ret = regulator_enable(qphy->vdda_phy_dpdm);
>> +     if (ret) {
>> +             dev_err(dev, "Unable to enable vdda-phy-dpdm:%d\n", ret);
>> +             goto disable_vdda_pll;
>> +     }
>> +
>> +     qphy->pwr_enabled = true;
>> +     dev_dbg(dev, "%s() regulators are turned on.\n", __func__);
>> +
>> +     return ret;
>> +
>> +disable_vdda_phy_dpdm:
>> +     regulator_disable(qphy->vdda_phy_dpdm);
>> +disable_vdda_pll:
>> +     regulator_disable(qphy->vdda_pll);
>> +disable_vdd_phy:
>> +     regulator_disable(qphy->vdd_phy);
>> +err_vdd_phy:
>> +     qphy->pwr_enabled = false;
>> +     dev_dbg(dev, "%s() regulators are turned off.\n", __func__);
>> +     return ret;
>> +}
>> +
>> +/*
>> + * Fetches HS Tx tuning value from e-fuse and sets QUSB2PHY_PORT_TUNE2
>> + * register.
>> + * For any error case, skip setting the value and use the default value.
>> + */
>> +static int qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
>> +{
>> +     struct device *dev = &qphy->phy->dev;
>> +     struct nvmem_cell *cell;
>> +     unsigned int bit_mask;
>> +     u32 tune2_val;
>> +     int bit_offset = 0;
>> +     int bit_len = 0;
>> +     ssize_t len;
>> +     u32 *val;
>> +     int ret;
>> +
>> +     /*
>> +      * Read EFUSE register having TUNE2 parameter's high nibble.
>> +      * If efuse register shows value as 0x0, or if we fail to find
>> +      * a valid efuse register settings, then use default value
>> +      * as 0xB for high nibble that we have already set while
>> +      * configuring phy.
>> +      */
>> +     cell = devm_nvmem_cell_get(dev, "tune2_hstx_trim_efuse");
>> +     if (IS_ERR(cell)) {
>> +             if (PTR_ERR(cell) == -EPROBE_DEFER)
>> +                     return PTR_ERR(cell);
>> +             goto skip;
>> +     }
>> +
>> +     val = (u32 *)nvmem_cell_read(cell, &len);
>> +     if (!IS_ERR(val)) {
>> +             ret = of_property_read_u32(dev->of_node,
>> +                                             "qcom,hstx-trim-bit-offset",
>> +                                             &bit_offset);
>> +             if (ret) {
>> +                     dev_dbg(dev, "hstx-trim bit offset is invalid.\n");
>> +                     goto skip;
>> +             }
>> +
>> +             ret = of_property_read_u32(dev->of_node,
>> +                                             "qcom,hstx-trim-bit-len",
>> +                                             &bit_len);
>> +             if (ret) {
>> +                     dev_dbg(dev, "hstx-trim bit length is invalid.\n");
>> +                     goto skip;
>> +             }
>> +
>> +             bit_mask = (1 << bit_len) - 1;
>> +             dev_dbg(dev,
>> +                     "%s(): efuse value:%x, bit_mask:%x, bit_offset: %d\n",
>> +                     __func__, val[0], bit_mask, bit_offset);
>> +             tune2_val = TUNE2_HIGH_NIBBLE_VAL(val[0], bit_offset, bit_mask);
>> +             if (!tune2_val) {
>> +                     dev_dbg(dev, "hstx-trim bit length is invalid.\n");
>> +                     goto skip;
>> +             }
>> +
>> +             /* Fused TUNE2 value is the higher nibble only */
>> +             tune2_val = tune2_val << 0x4;
>> +             qusb2_set_bits(qphy->base + QUSB2PHY_PORT_TUNE2, tune2_val);
>> +     } else {
>> +             dev_dbg(dev, "failed reading hs-tx trim value: %d\n", ret);
>> +     }
>> +
>> +skip:
>> +     return 0;
>> +}
>> +
>> +static int qusb2_phy_init(struct phy *phy)
>> +{
>> +     struct qusb2_phy *qphy = phy_get_drvdata(phy);
>> +     unsigned int reset_val;
>> +     unsigned int clk_scheme;
>> +     bool is_se_clk = false;
>> +     int ret;
>> +
>> +     dev_info(&phy->dev, "Initializing QUSB2 phy\n");
>
> dev_vdbg here..

okay.

>> +
>> +     ret = qusb2_phy_enable_power(qphy, true);
>> +     if (ret)
>> +             return ret;
>
> shouldn't this be done in power_on?

Okay, will add power_on/off() callbacks and move this code there.

>> +
>> +     qusb2_phy_enable_clocks(qphy, true);
>> +
>> +     /* Perform phy reset */
>> +     ret = reset_control_assert(qphy->phy_reset);
>> +     if (ret) {
>> +             dev_err(&phy->dev, "Failed to assert phy_reset\n");
>> +             return ret;
>> +     }
>> +     usleep_range(100, 150);
>
> add a comment for the above delay.

sure.

>> +     ret = reset_control_deassert(qphy->phy_reset);
>> +     if (ret) {
>> +             dev_err(&phy->dev, "Failed to de-assert phy_reset\n");
>> +             return ret;
>> +     }
>> +
>> +     /* Disable the PHY */
>> +     qusb2_set_bits(qphy->base + QUSB2PHY_PORT_POWERDOWN,
>> +                     CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
>> +
>> +     /* save reset value to override based on clk scheme */
>> +     reset_val = readl_relaxed(qphy->base + QUSB2PHY_PLL_TEST);
>> +
>> +     qcom_qusb2_phy_configure(qphy->base, qphy->cfg->phy_init_tbl,
>> +                             qphy->cfg->phy_init_tbl_sz);
>> +
>> +     /* Check for efuse value for tuning the PHY */
>> +     ret = qusb2_phy_set_tune2_param(qphy);
>> +     if (ret)
>> +             return ret;
>> +
>> +     /* Enable the PHY */
>> +     qusb2_clr_bits(qphy->base + QUSB2PHY_PORT_POWERDOWN, POWER_DOWN);
>> +
>> +     /* Require to get phy pll lock successfully */
>> +     usleep_range(150, 160);
>> +
>> +     /*
>> +      * Use differential clk by default; later we read TCSR_PHY_CLK_SCHEME
>> +      * register to check if Single-ended clock scheme is selected. If yes,
>> +      * then disable differential ref_clk and use single-ended clock.
>> +      */
>> +
>> +     if (qphy->tcsr) {
>> +             ret = regmap_read(qphy->tcsr, qphy->clk_scheme_offset,
>> +                                                     &clk_scheme);
>> +             /* is SE-clk available ? */
>> +             if (clk_scheme & PHY_CLK_SCHEME_SEL) {
>> +                     dev_dbg(&phy->dev, "%s: select single-ended clk src\n",
>> +                                                             __func__);
>> +                     is_se_clk = true;
>> +             }
>> +     }
>> +
>> +     if (is_se_clk) {
>> +             reset_val |= CLK_REF_SEL;
>> +             clk_disable_unprepare(qphy->ref_clk);
>> +     } else {
>> +             reset_val &= ~CLK_REF_SEL;
>> +             clk_prepare_enable(qphy->ref_clk);
>> +     }
>> +
>> +     writel_relaxed(reset_val, qphy->base + QUSB2PHY_PLL_TEST);
>> +
>> +     /* Make sure that above write is completed to get PLL source clock */
>> +     wmb();
>> +
>> +     /* Required to get PHY PLL lock successfully */
>> +     usleep_range(100, 110);
>> +
>> +     if (!(readb_relaxed(qphy->base + QUSB2PHY_PLL_STATUS) &
>> +                                     PLL_LOCKED)) {
>> +             dev_err(&phy->dev, "QUSB PHY PLL LOCK fails:%x\n",
>> +                     readb_relaxed(qphy->base + QUSB2PHY_PLL_STATUS));
>> +             return -EBUSY;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int qusb2_phy_exit(struct phy *phy)
>> +{
>> +     struct qusb2_phy *qphy = phy_get_drvdata(phy);
>> +
>> +     /* Disable the PHY */
>> +     qusb2_set_bits(qphy->base + QUSB2PHY_PORT_POWERDOWN,
>> +                     CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
>> +
>> +     qusb2_phy_enable_clocks(qphy, false);
>> +     qusb2_phy_enable_power(qphy, false);
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct phy_ops qusb2_phy_gen_ops = {
>> +     .init           = qusb2_phy_init,
>> +     .exit           = qusb2_phy_exit,
>
> you can add callbacks for power_on and power_off and add then enable clocks and
> power here?

Yes, will do that.

>
>> +     .owner          = THIS_MODULE,
>> +};
>> +
>> +static const struct of_device_id qusb2_phy_of_match_table[] = {
>> +     {
>> +             .compatible     = "qcom,msm8996-qusb2-phy",
>> +             .data           = &msm8996_phy_init_cfg,
>> +     },
>> +     { },
>> +};
>> +MODULE_DEVICE_TABLE(of, qusb2_phy_of_match_table);
>> +
>> +static int qusb2_phy_probe(struct platform_device *pdev)
>> +{
>> +     struct device *dev = &pdev->dev;
>> +     struct qusb2_phy *qphy;
>> +     struct phy_provider *phy_provider;
>> +     struct phy *generic_phy;
>> +     const struct of_device_id *match;
>> +     struct resource *res;
>> +     int ret = 0;
>> +
>> +     qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
>> +     if (!qphy)
>> +             return -ENOMEM;
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     if (!res)
>> +             return -ENODEV;
>
> the above check is not required. ioremap will take care.

okay, will remove this.

>> +     qphy->base = devm_ioremap_resource(dev, res);
>> +     if (IS_ERR(qphy->base))
>> +             return PTR_ERR(qphy->base);
>> +
>> +     qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb_clk");
>> +     if (IS_ERR(qphy->cfg_ahb_clk)) {
>> +             ret = PTR_ERR(qphy->cfg_ahb_clk);
>> +             if (ret != -EPROBE_DEFER)
>> +                     dev_err(dev, "failed to get cfg_ahb_clk\n");
>> +             return ret;
>> +     }
>> +
>> +     qphy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
>> +     if (IS_ERR(qphy->ref_clk_src)) {
>> +             qphy->ref_clk_src = NULL;
>> +             ret = PTR_ERR(qphy->ref_clk_src);
>> +             if (ret != -EPROBE_DEFER)
>> +                     dev_dbg(dev, "clk get failed for ref_clk_src\n");
>
> don't we have to return on PROBE_DEFER?

yes, we do need to return here.

>> +     }
>> +
>> +     qphy->ref_clk = devm_clk_get(dev, "ref_clk");
>> +     if (IS_ERR(qphy->ref_clk)) {
>> +             qphy->ref_clk = NULL;
>> +             ret = PTR_ERR(qphy->ref_clk);
>> +             if (ret != -EPROBE_DEFER)
>> +                     dev_dbg(dev, "clk get failed for ref_clk\n");
>
> same here.

right, will return on EPROBE_DEFER.

>> +     } else {
>> +             clk_set_rate(qphy->ref_clk, 19200000);
>> +     }
>> +
>> +     qphy->iface_clk = devm_clk_get(dev, "iface_clk");
>> +     if (IS_ERR(qphy->iface_clk)) {
>> +             qphy->iface_clk = NULL;
>> +             ret = PTR_ERR(qphy->iface_clk);
>> +             if (ret != -EPROBE_DEFER)
>> +                     dev_dbg(dev, "clk get failed for iface_clk\n");
>
> here..

yup.

>> +     }
>> +
>> +     qphy->phy_reset = devm_reset_control_get(&pdev->dev, "phy");
>> +     if (IS_ERR(qphy->phy_reset)) {
>> +             dev_err(dev, "failed to get phy core reset\n");
>> +             return PTR_ERR(qphy->phy_reset);
>> +     }
>> +
>> +     qphy->vdd_phy = devm_regulator_get(dev, "vdd-phy");
>> +     if (IS_ERR(qphy->vdd_phy)) {
>> +             dev_err(dev, "unable to get vdd-phy supply\n");
>> +             return PTR_ERR(qphy->vdd_phy);
>> +     }
>> +
>> +     qphy->vdda_pll = devm_regulator_get(dev, "vdda-pll");
>> +     if (IS_ERR(qphy->vdda_pll)) {
>> +             dev_err(dev, "unable to get vdda-pll supply\n");
>> +             return PTR_ERR(qphy->vdda_pll);
>> +     }
>> +
>> +     qphy->vdda_phy_dpdm = devm_regulator_get(dev, "vdda-phy-dpdm");
>> +     if (IS_ERR(qphy->vdda_phy_dpdm)) {
>> +             dev_err(dev, "unable to get vdda-phy-dpdm supply\n");
>> +             return PTR_ERR(qphy->vdda_phy_dpdm);
>> +     }
>> +
>> +     /* Get the specific init parameters of QMP phy */
>> +     match = of_match_node(qusb2_phy_of_match_table, dev->of_node);
>> +     qphy->cfg = match->data;
>> +
>> +     qphy->tcsr = syscon_regmap_lookup_by_phandle(dev->of_node,
>> +                                                     "qcom,tcsr-syscon");
>> +     if (!IS_ERR(qphy->tcsr)) {
>> +             ret = of_property_read_u32(dev->of_node, "qcom,phy-clk-scheme",
>> +                                             &qphy->clk_scheme_offset);
>> +             if (ret) {
>> +                     dev_err(dev, "phy-clk-scheme reg offset is invalid\n");
>> +                     qphy->tcsr = NULL;
>> +                     return ret;
>> +             }
>> +     } else {
>> +             dev_dbg(dev, "Failed to lookup TCSR regmap\n");
>> +             qphy->tcsr = NULL;
>> +     }
>> +
>> +     phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
>> +     if (IS_ERR(phy_provider)) {
>> +             ret = PTR_ERR(phy_provider);
>> +             dev_err(dev, "%s: failed to register phy %d\n", __func__, ret);
>> +             return ret;
>> +     }
>> +
>> +     generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops);
>> +     if (IS_ERR(generic_phy)) {
>> +             ret = PTR_ERR(generic_phy);
>> +             dev_err(dev, "%s: failed to create phy %d\n", __func__, ret);
>> +             generic_phy = NULL;
>> +             return ret;
>> +     }
>
> phy should be created before registering the PHY.
>> +     qphy->phy = generic_phy;
>> +
>> +     dev_set_drvdata(dev, qphy);
>> +     phy_set_drvdata(generic_phy, qphy);
>
> this should be done before phy_provider_register.

will move the code as suggested.


Thanks
Vivek

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH] ARM: dts: r8a7794: remove Z clock
From: Geert Uytterhoeven @ 2016-11-02  8:50 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Simon Horman, Linux-Renesas, Rob Herring, Mark Rutland,
	devicetree@vger.kernel.org, Magnus Damm, Russell King,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <2289596.xFBEUD1OgK@wasted.cogentembedded.com>

On Sat, Oct 29, 2016 at 11:31 PM, Sergei Shtylyov
<sergei.shtylyov@cogentembedded.com> wrote:
> R8A7794 doesn't have Cortex-A15 CPUs, thus there's no Z clock...
>
> Fixes: 0dce5454d5c2 ("ARM: shmobile: Initial r8a7794 SoC device tree")
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

> ---
> The patch is against the 'master' branch of Simon Horman's 'renesas.git' repo.
>
>  arch/arm/boot/dts/r8a7794.dtsi            |    3 +--
>  include/dt-bindings/clock/r8a7794-clock.h |    3 +--
>  2 files changed, 2 insertions(+), 4 deletions(-)
>
> Index: renesas/arch/arm/boot/dts/r8a7794.dtsi
> ===================================================================
> --- renesas.orig/arch/arm/boot/dts/r8a7794.dtsi
> +++ renesas/arch/arm/boot/dts/r8a7794.dtsi
> @@ -1025,8 +1025,7 @@
>                         clocks = <&extal_clk &usb_extal_clk>;
>                         #clock-cells = <1>;
>                         clock-output-names = "main", "pll0", "pll1", "pll3",
> -                                            "lb", "qspi", "sdh", "sd0", "z",
> -                                            "rcan";
> +                                            "lb", "qspi", "sdh", "sd0", "rcan";
>                         #power-domain-cells = <0>;
>                 };
>                 /* Variable factor clocks */
> Index: renesas/include/dt-bindings/clock/r8a7794-clock.h
> ===================================================================
> --- renesas.orig/include/dt-bindings/clock/r8a7794-clock.h
> +++ renesas/include/dt-bindings/clock/r8a7794-clock.h
> @@ -20,8 +20,7 @@
>  #define R8A7794_CLK_QSPI               5
>  #define R8A7794_CLK_SDH                        6
>  #define R8A7794_CLK_SD0                        7
> -#define R8A7794_CLK_Z                  8
> -#define R8A7794_CLK_RCAN               9
> +#define R8A7794_CLK_RCAN               8

JFTR, this changes the bindings file, but the values are solely used
for indexing
the clock-output-names array, so this is fine.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 2/2] mmc: sdhci: Use sdhci-caps-mask and sdhci-caps to change the caps read during __sdhci_read_caps
From: Adrian Hunter @ 2016-11-02  8:39 UTC (permalink / raw)
  To: Zach Brown, ulf.hansson-QSEj5FYQhm4dnm+yROfE0A
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1477670171-30015-3-git-send-email-zach.brown-acOepvfBmUk@public.gmane.org>

On 28/10/16 18:56, Zach Brown wrote:
> The sdhci capabilities register can be incorrect. The sdhci-caps-mask
> and sdhci-caps dt properties specify which bits of the register are
> incorrect and what their values should be. This patch makes the sdhci
> driver use those properties to correct the caps during
> __sdhci_read_caps.
> 
> During __sdhci_read_caps
> Use the sdhci-caps-mask property to turn off the incorrect bits of the
> sdhci register after reading them.
> Use the sdhci-caps to turn on bits after using sdhci-caps-mask to turn
> off the incorrect ones.
> 
> Signed-off-by: Zach Brown <zach.brown-acOepvfBmUk@public.gmane.org>

Apart from minor style issue:

Acked-by: Adrian Hunter <adrian.hunter-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

> ---
>  drivers/mmc/host/sdhci.c | 24 ++++++++++++++++++++++--
>  1 file changed, 22 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 1e25b01..d5feae4 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -22,6 +22,7 @@
>  #include <linux/scatterlist.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/of.h>
>  
>  #include <linux/leds.h>
>  
> @@ -2991,6 +2992,8 @@ static int sdhci_set_dma_mask(struct sdhci_host *host)
>  void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
>  {
>  	u16 v;
> +	u64 dt_caps_mask = 0;
> +	u64 dt_caps = 0;
>  
>  	if (host->read_caps)
>  		return;
> @@ -3005,18 +3008,35 @@ void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
>  
>  	sdhci_do_reset(host, SDHCI_RESET_ALL);
>  
> +	of_property_read_u64(mmc_dev(host->mmc)->of_node,
> +			     "sdhci-caps-mask", &dt_caps_mask);
> +	of_property_read_u64(mmc_dev(host->mmc)->of_node,
> +			     "sdhci-caps", &dt_caps);
> +
>  	v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
>  	host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
>  
>  	if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
>  		return;
>  
> -	host->caps = caps ? *caps : sdhci_readl(host, SDHCI_CAPABILITIES);
> +	if (caps)
> +		host->caps = *caps;
> +	else {

All branches of 'if' should have {}.
i.e. refer results of ./scripts/checkpatch.pl --strict

> +		host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
> +		host->caps &= ~lower_32_bits(dt_caps_mask);
> +		host->caps |= lower_32_bits(dt_caps);
> +	}
>  
>  	if (host->version < SDHCI_SPEC_300)
>  		return;
>  
> -	host->caps1 = caps1 ? *caps1 : sdhci_readl(host, SDHCI_CAPABILITIES_1);
> +	if (caps1)
> +		host->caps1 = *caps1;
> +	else {

Ditto

> +		host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
> +		host->caps1 &= ~upper_32_bits(dt_caps_mask);
> +		host->caps1 |= upper_32_bits(dt_caps);
> +	}
>  }
>  EXPORT_SYMBOL_GPL(__sdhci_read_caps);
>  
> 

--
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 1/2] phy: qcom-qusb2: New driver for QUSB2 PHY on Qcom chips
From: Vivek Gautam @ 2016-11-02  8:11 UTC (permalink / raw)
  To: Rob Herring
  Cc: kishon, Mark Rutland, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arm-msm, Srinivas Kandagatla
In-Reply-To: <20161026211611.3rl7mas75ju4x77w@rob-hp-laptop>

Hi Rob,


On Thu, Oct 27, 2016 at 2:46 AM, Rob Herring <robh@kernel.org> wrote:
> On Wed, Oct 19, 2016 at 04:13:46PM +0530, Vivek Gautam wrote:
>> PHY transceiver driver for QUSB2 phy controller that provides
>> HighSpeed functionality for DWC3 controller present on
>> Qualcomm chipsets.
>>
>> This driver is based on phy-msm-qusb driver available in
>> msm-4.4 kernel @codeaurora[1]
>>
>> [1] https://source.codeaurora.org/quic/la/kernel/msm-4.4/log/?h=caf/3.18/msm-3.18
>>
>> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
>> Cc: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>  .../devicetree/bindings/phy/qcom-qusb2-phy.txt     |  37 ++
>
> It's preferred the bindings are a separate patch.

Sure, will prepare a separate patch for bindings doc for both the phy patches.

>
>>  drivers/phy/Kconfig                                |  10 +
>>  drivers/phy/Makefile                               |   1 +
>>  drivers/phy/phy-qcom-qusb2.c                       | 577 +++++++++++++++++++++
>>  4 files changed, 625 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>>  create mode 100644 drivers/phy/phy-qcom-qusb2.c
>>
>> diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>> new file mode 100644
>> index 0000000..97c9ce7
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>> @@ -0,0 +1,37 @@
>> +Qualcomm QUSB2 phy controller
>> +=============================
>> +
>> +QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
>> +
>> +Required properties:
>> + - compatible: compatible list, contains "qcom,msm8996-qusb2-phy".
>> + - reg: offset and length of the PHY register set.
>> + - #phy-cells: must be 0.
>> +
>> + - clocks: a list of phandles and clock-specifier pairs,
>> +        one for each entry in clock-names.
>> + - clock-names: must be "cfg_ahb" for phy config clock,
>> +                     "ref_clk" for 19.2 MHz ref clk,
>> +                     "ref_clk_src" reference clock source.
>> +                     "iface" for phy interface clock (Optional).
>> +
>> + - vdd-phy-supply: Phandle to a regulator supply to PHY core block.
>> + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
>> + - vdda-phy-dpdm: Phandle to 3.1V regulator supply to Dp/Dm port signals.
>> +
>> + - resets: a list of phandles and reset controller specifier pairs,
>> +        one for each entry in reset-names.
>> + - reset-names: must be "phy" for reset of phy block.
>> +
>> +Optional properties:
>> + - nvmem-cells: a list of phandles to nvmem cells that contain fused
>> +             tuning parameters for qusb2 phy, one for each entry
>> +             in nvmem-cell-names.
>> + - nvmem-cell-names: must be "tune2_hstx_trim_efuse" for cell containing
>> +                  HS Tx trim value.
>> + - qcom,hstx-trim-bit-offset: bit offset within nvmem cell for
>> +                           HS Tx trim value.
>> + - qcom,hstx-trim-bit-len: bit length of HS Tx trim value within nvmem cell.
>
> When does this change? Why is it not just a different nvmem cell?

This is per-controller bit fields. So for example, msm8996 that
has couple of controllers, has these bits as a part of same
cell of 32bits. Bits 21:24 for controller-1, and 25-28 for controller-2.

I thought of using the 'reg' and 'bit' properties of nvmem cell,
but was unsuccessful in using the same.

Hi Srini,
Can you please help me with this ? We have one register of 32 bits
(representing one nvmem cell), that has the value for both the
QUSB2 controllers. So, we just need to read the values that are placed
in two different nibbles, for the two controllers, using nvmem cell
device tree properties (may be 'reg' and 'bit' properties).


Thanks
Vivek

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH v4 20/23] ARM: shmobile: rcar-gen2: Stop passing mode pins state to clock driver
From: Geert Uytterhoeven @ 2016-11-02  8:09 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Geert Uytterhoeven, Philipp Zabel, Michael Turquette,
	Stephen Boyd, Simon Horman, Magnus Damm,
	devicetree@vger.kernel.org, Linux-Renesas,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <722d91fe-574a-8613-34ff-d44be19157be@cogentembedded.com>

On Tue, Nov 1, 2016 at 2:35 PM, Sergei Shtylyov
<sergei.shtylyov@cogentembedded.com> wrote:
>> --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c
>> +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c
>
> [...]
>>
>> @@ -130,7 +129,7 @@ void __init rcar_gen2_timer_init(void)
>>         iounmap(base);
>>  #endif /* CONFIG_ARM_ARCH_TIMER */
>>
>> -       rcar_gen2_clocks_init(mode);
>> +       of_clk_init(NULL);
>>         clocksource_probe();
>>  }
>>
>
>   This hunk no longer applies to devel.

Indeed, but I can't update it, as we can't have all mach-shmobile changes in
the clock tree. So Simon will have to resolve the conflict later.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCHv2 3/4] mfd: altr-a10sr: Add Arria10 SR Monitor
From: Lee Jones @ 2016-11-02  8:01 UTC (permalink / raw)
  To: Thor Thayer
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	dinguyen-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw, arnd-r2nGTMty4D4,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, geert-Td1EMuHUCqxL1ZNQvxDV9g,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <39faa26d-ca05-d68d-a50a-03d09d445b77-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>

On Mon, 31 Oct 2016, Thor Thayer wrote:
> On 10/31/2016 03:02 AM, Lee Jones wrote:
> > On Thu, 27 Oct 2016, tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org wrote:
> > 
> > > From: Thor Thayer <tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
> > > 
> > > Add the Altera Arria10 DevKit System Resource Monitor functionality
> > > to the MFD device.
> > > 
> > > Signed-off-by: Thor Thayer <tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
> > > ---
> > > v2  Change from -mon to -monitor for clarity
> > > ---
> > >  drivers/mfd/altera-a10sr.c | 4 ++++
> > >  1 file changed, 4 insertions(+)
> > > 
> > > diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c
> > > index 06e1f7f..30de652 100644
> > > --- a/drivers/mfd/altera-a10sr.c
> > > +++ b/drivers/mfd/altera-a10sr.c
> > > @@ -33,6 +33,10 @@
> > >  		.name = "altr_a10sr_gpio",
> > >  		.of_compatible = "altr,a10sr-gpio",
> > >  	},
> > > +	{
> > > +		.name = "altr_a10sr_monitor",
> > > +		.of_compatible = "altr,a10sr-monitor",
> > 
> > So long as you use whichever compatible you agree on with Rob:
> > 
> > For my own reference:
> >   Acked-for-MFD-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > 
> I'm getting a "Non-standard signature" warning for this (even if I make
> everything lower-case).
> 
> Would you prefer I submit it with the warning or should I change it to
> "Acked-by"?

Please submit it as you see it.  I will amend when applying.

> Thanks for reviewing!
> 
> Thor
> 
> > > +	},
> > >  };
> > > 
> > >  static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg)
> > 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
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 3/3] ipmi/bt-bmc: add a sysfs file to configure a maximum response time
From: Cédric Le Goater @ 2016-11-02  7:57 UTC (permalink / raw)
  To: Corey Minyard, openipmi-developer, Joel Stanley
  Cc: devicetree, Rob Herring, linux-arm-kernel, Arnd Bergmann,
	Cédric Le Goater
In-Reply-To: <1478073426-3714-1-git-send-email-clg@kaod.org>

We could also use an ioctl for that purpose. sysfs seems a better
approach.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 drivers/char/ipmi/bt-bmc.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
index e751e4a754b7..d7146f0e900e 100644
--- a/drivers/char/ipmi/bt-bmc.c
+++ b/drivers/char/ipmi/bt-bmc.c
@@ -84,6 +84,33 @@ struct bt_bmc {
 
 static atomic_t open_count = ATOMIC_INIT(0);
 
+static ssize_t bt_bmc_show_response_time(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct bt_bmc *bt_bmc = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE - 1, "%d\n", bt_bmc->response_time);
+}
+
+static ssize_t bt_bmc_set_response_time(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct bt_bmc *bt_bmc = dev_get_drvdata(dev);
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 0, &val);
+	if (err)
+		return err;
+	bt_bmc->response_time = val;
+	return count;
+}
+
+static DEVICE_ATTR(response_time, 0644,
+		   bt_bmc_show_response_time, bt_bmc_set_response_time);
+
 static u8 bt_inb(struct bt_bmc *bt_bmc, int reg)
 {
 	return ioread8(bt_bmc->base + reg);
@@ -572,6 +599,10 @@ static int bt_bmc_probe(struct platform_device *pdev)
 	bt_bmc_config_irq(bt_bmc, pdev);
 
 	bt_bmc->response_time = BT_BMC_RESPONSE_TIME;
+	rc = device_create_file(&pdev->dev, &dev_attr_response_time);
+	if (rc)
+		dev_warn(&pdev->dev, "can't create response_time file\n");
+
 
 	if (bt_bmc->irq) {
 		dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 2/3] ipmi/bt-bmc: maintain a request expiry list
From: Cédric Le Goater @ 2016-11-02  7:57 UTC (permalink / raw)
  To: Corey Minyard, openipmi-developer, Joel Stanley
  Cc: devicetree, Rob Herring, linux-arm-kernel, Arnd Bergmann,
	Cédric Le Goater
In-Reply-To: <1478073426-3714-1-git-send-email-clg@kaod.org>

Regarding the response expiration handling, the IPMI spec says :

   The BMC must not return a given response once the corresponding
   Request-to-Response interval has passed. The BMC can ensure this
   by maintaining its own internal list of outstanding requests through
   the interface. The BMC could age and expire the entries in the list
   by expiring the entries at an interval that is somewhat shorter than
   the specified Request-to-Response interval....

To handle such case, we maintain list of received requests using the
seq number of the BT message to identify them. The list is updated
each time a request is received and a response is sent. The expiration
of the reponses is handled at each updates but also with a timer.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 drivers/char/ipmi/bt-bmc.c | 132 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)

diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
index fc9e8891eae3..e751e4a754b7 100644
--- a/drivers/char/ipmi/bt-bmc.c
+++ b/drivers/char/ipmi/bt-bmc.c
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/timer.h>
 
 /*
@@ -57,6 +58,15 @@
 
 #define BT_BMC_BUFFER_SIZE 256
 
+#define BT_BMC_RESPONSE_TIME	5 /* seconds */
+
+struct ipmi_request {
+	struct list_head list;
+
+	u8 seq;
+	unsigned long expires;
+};
+
 struct bt_bmc {
 	struct device		dev;
 	struct miscdevice	miscdev;
@@ -65,6 +75,11 @@ struct bt_bmc {
 	wait_queue_head_t	queue;
 	struct timer_list	poll_timer;
 	struct mutex		mutex;
+
+	unsigned int		response_time;
+	struct timer_list	requests_timer;
+	spinlock_t              requests_lock;
+	struct list_head        requests;
 };
 
 static atomic_t open_count = ATOMIC_INIT(0);
@@ -163,6 +178,94 @@ static int bt_bmc_open(struct inode *inode, struct file *file)
 }
 
 /*
+ * lock should be held
+ */
+static void drop_expired_requests(struct bt_bmc *bt_bmc)
+{
+	unsigned long flags = 0;
+	struct ipmi_request *req, *next;
+	unsigned long next_expires = 0;
+	int start_timer = 0;
+
+	spin_lock_irqsave(&bt_bmc->requests_lock, flags);
+	list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
+		if (time_after_eq(jiffies, req->expires)) {
+			pr_warn("BT: request seq:%d has expired. dropping\n",
+				req->seq);
+			list_del(&req->list);
+			kfree(req);
+			continue;
+		}
+		if (!start_timer) {
+			start_timer = 1;
+			next_expires = req->expires;
+		} else {
+			next_expires = min(next_expires, req->expires);
+		}
+	}
+	spin_unlock_irqrestore(&bt_bmc->requests_lock, flags);
+
+	/* and possibly restart */
+	if (start_timer)
+		mod_timer(&bt_bmc->requests_timer, next_expires);
+}
+
+static void requests_timer(unsigned long data)
+{
+	struct bt_bmc *bt_bmc = (void *)data;
+
+	drop_expired_requests(bt_bmc);
+}
+
+static int bt_bmc_add_request(struct bt_bmc *bt_bmc, u8 seq)
+{
+	struct ipmi_request *req;
+
+	req = kmalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	req->seq = seq;
+	req->expires = jiffies +
+		msecs_to_jiffies(bt_bmc->response_time * 1000);
+
+	spin_lock(&bt_bmc->requests_lock);
+	list_add(&req->list, &bt_bmc->requests);
+	spin_unlock(&bt_bmc->requests_lock);
+
+	drop_expired_requests(bt_bmc);
+	return 0;
+}
+
+static int bt_bmc_remove_request(struct bt_bmc *bt_bmc, u8 seq)
+{
+	struct ipmi_request *req, *next;
+	int ret = -EBADRQC; /* Invalid request code */
+
+	spin_lock(&bt_bmc->requests_lock);
+	list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
+		/*
+		 * The sequence number should be unique, so remove the
+		 * first matching request found. If there are others,
+		 * they should expire
+		 */
+		if (req->seq == seq) {
+			list_del(&req->list);
+			kfree(req);
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock(&bt_bmc->requests_lock);
+
+	if (ret)
+		pr_warn("BT: request seq:%d is invalid\n", seq);
+
+	drop_expired_requests(bt_bmc);
+	return ret;
+}
+
+/*
  * The BT (Block Transfer) interface means that entire messages are
  * buffered by the host before a notification is sent to the BMC that
  * there is data to be read. The first byte is the length and the
@@ -231,6 +334,13 @@ static ssize_t bt_bmc_read(struct file *file, char __user *buf,
 		len_byte = 0;
 	}
 
+	if (ret > 0) {
+		int ret2 = bt_bmc_add_request(bt_bmc, kbuffer[2]);
+
+		if (ret2)
+			ret = ret2;
+	}
+
 	clr_b_busy(bt_bmc);
 
 out_unlock:
@@ -283,12 +393,20 @@ static ssize_t bt_bmc_write(struct file *file, const char __user *buf,
 	clr_wr_ptr(bt_bmc);
 
 	while (count) {
+		int ret2;
+
 		nwritten = min_t(ssize_t, count, sizeof(kbuffer));
 		if (copy_from_user(&kbuffer, buf, nwritten)) {
 			ret = -EFAULT;
 			break;
 		}
 
+		ret2 = bt_bmc_remove_request(bt_bmc, kbuffer[2]);
+		if (ret2) {
+			ret = ret2;
+			break;
+		}
+
 		bt_writen(bt_bmc, kbuffer, nwritten);
 
 		count -= nwritten;
@@ -438,6 +556,8 @@ static int bt_bmc_probe(struct platform_device *pdev)
 
 	mutex_init(&bt_bmc->mutex);
 	init_waitqueue_head(&bt_bmc->queue);
+	INIT_LIST_HEAD(&bt_bmc->requests);
+	spin_lock_init(&bt_bmc->requests_lock);
 
 	bt_bmc->miscdev.minor	= MISC_DYNAMIC_MINOR,
 		bt_bmc->miscdev.name	= DEVICE_NAME,
@@ -451,6 +571,8 @@ static int bt_bmc_probe(struct platform_device *pdev)
 
 	bt_bmc_config_irq(bt_bmc, pdev);
 
+	bt_bmc->response_time = BT_BMC_RESPONSE_TIME;
+
 	if (bt_bmc->irq) {
 		dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
 	} else {
@@ -468,6 +590,9 @@ static int bt_bmc_probe(struct platform_device *pdev)
 		  BT_CR0_ENABLE_IBT,
 		  bt_bmc->base + BT_CR0);
 
+	setup_timer(&bt_bmc->requests_timer, requests_timer,
+		    (unsigned long)bt_bmc);
+
 	clr_b_busy(bt_bmc);
 
 	return 0;
@@ -476,10 +601,17 @@ static int bt_bmc_probe(struct platform_device *pdev)
 static int bt_bmc_remove(struct platform_device *pdev)
 {
 	struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
+	struct ipmi_request *req, *next;
 
 	misc_deregister(&bt_bmc->miscdev);
 	if (!bt_bmc->irq)
 		del_timer_sync(&bt_bmc->poll_timer);
+
+	del_timer_sync(&bt_bmc->requests_timer);
+	list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
+		list_del(&req->list);
+		kfree(req);
+	}
 	return 0;
 }
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 1/3] ipmi/bt-bmc: change compatible node to 'aspeed, ast2400-ibt-bmc'
From: Cédric Le Goater @ 2016-11-02  7:57 UTC (permalink / raw)
  To: Corey Minyard, openipmi-developer, Joel Stanley
  Cc: devicetree, Rob Herring, linux-arm-kernel, Arnd Bergmann,
	Cédric Le Goater
In-Reply-To: <1478073426-3714-1-git-send-email-clg@kaod.org>

The Aspeed SoCs have two BT interfaces : one is IPMI compliant and the
other is H8S/2168 compliant.

The current ipmi/bt-bmc driver implements the IPMI version and we
should reflect its nature in the compatible node name using
'aspeed,ast2400-ibt-bmc' instead of 'aspeed,ast2400-bt-bmc'. The
latter should be used for a H8S interface driver if it is implemented
one day.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 .../ipmi/{aspeed,ast2400-bt-bmc.txt => aspeed,ast2400-ibt-bmc.txt}    | 4 ++--
 drivers/char/ipmi/bt-bmc.c                                            | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)
 rename Documentation/devicetree/bindings/ipmi/{aspeed,ast2400-bt-bmc.txt => aspeed,ast2400-ibt-bmc.txt} (85%)

diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-bt-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
similarity index 85%
rename from Documentation/devicetree/bindings/ipmi/aspeed,ast2400-bt-bmc.txt
rename to Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
index fbbacd958240..6f28969af9dc 100644
--- a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-bt-bmc.txt
+++ b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
@@ -6,7 +6,7 @@ perform in-band IPMI communication with their host.
 
 Required properties:
 
-- compatible : should be "aspeed,ast2400-bt-bmc"
+- compatible : should be "aspeed,ast2400-ibt-bmc"
 - reg: physical address and size of the registers
 
 Optional properties:
@@ -17,7 +17,7 @@ Optional properties:
 Example:
 
 	ibt@1e789140 {
-		compatible = "aspeed,ast2400-bt-bmc";
+		compatible = "aspeed,ast2400-ibt-bmc";
 		reg = <0x1e789140 0x18>;
 		interrupts = <8>;
 	};
diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
index b49e61320952..fc9e8891eae3 100644
--- a/drivers/char/ipmi/bt-bmc.c
+++ b/drivers/char/ipmi/bt-bmc.c
@@ -484,7 +484,7 @@ static int bt_bmc_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id bt_bmc_match[] = {
-	{ .compatible = "aspeed,ast2400-bt-bmc" },
+	{ .compatible = "aspeed,ast2400-ibt-bmc" },
 	{ },
 };
 
@@ -502,4 +502,4 @@ module_platform_driver(bt_bmc_driver);
 MODULE_DEVICE_TABLE(of, bt_bmc_match);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alistair Popple <alistair@popple.id.au>");
-MODULE_DESCRIPTION("Linux device interface to the BT interface");
+MODULE_DESCRIPTION("Linux device interface to the IPMI BT interface");
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 0/3] ipmi/bt-bmc: fix compatible node and add a request expiry list
From: Cédric Le Goater @ 2016-11-02  7:57 UTC (permalink / raw)
  To: Corey Minyard, openipmi-developer, Joel Stanley
  Cc: devicetree, Rob Herring, linux-arm-kernel, Arnd Bergmann,
	Cédric Le Goater

Hello Corey,

Here is a short serie fixing the name of the device tree 'compatible'
node of the ipmi/bt-bmc driver and adding a request expiry list to the
driver.

The first patch should be considered as a 4.9 fix, if possible.

Thanks,

C.


Cédric Le Goater (3):
  ipmi/bt-bmc: change compatible node to 'aspeed,ast2400-ibt-bmc'
  ipmi/bt-bmc: maintain a request expiry list
  ipmi/bt-bmc: add a sysfs file to configure a maximum response time

 ...t2400-bt-bmc.txt => aspeed,ast2400-ibt-bmc.txt} |   4 +-
 drivers/char/ipmi/bt-bmc.c                         | 167 ++++++++++++++++++++-
 2 files changed, 167 insertions(+), 4 deletions(-)
 rename Documentation/devicetree/bindings/ipmi/{aspeed,ast2400-bt-bmc.txt => aspeed,ast2400-ibt-bmc.txt} (85%)

-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] soc: qcom: Add SoC info driver
From: Imran Khan @ 2016-11-02  7:49 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: andy.gross, David Brown, Rob Herring, Mark Rutland,
	open list:ARM/QUALCOMM SUPPORT, open list:ARM/QUALCOMM SUPPORT,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list
In-Reply-To: <9172138.R1PTFlLtP9@wuerfel>

On 10/27/2016 7:11 PM, Arnd Bergmann wrote:
> On Thursday, October 27, 2016 6:40:27 PM CEST Imran Khan wrote:
>> On 10/26/2016 8:16 PM, Arnd Bergmann wrote:
>>> On Wednesday, October 26, 2016 7:42:08 PM CEST Imran Khan wrote:
>>>> On 10/26/2016 7:35 PM, Arnd Bergmann wrote:
>>>>>>> As we are talking about generic soc_device_attribute fields, I was hoping that
>>>>>>> having a vendor field would be helpful as along with family it would provide
>>>>>>> a more thorough information. Also as more than one foundries may be used for 
>>>>>>> a soc, can we have a field say foundry_id to provide this information.
>>>>> My first feeling is that this 'vendor' information can should be
>>>>> derived from the family. It's also not clear what would happen
>>>>> to this when a company gets bought. E.g. the Oxnas product family
>>>>> was subsequently owned by Oxford, PLX, Avago and Broadcom, and the
>>>>> mxs family was Sigmatel, Freescale, now NXP and might soon be
>>>>> Qualcomm. What would you put in there in this case?
>>>>
>>>> Okay, not having vendor field is fine for me. Could you also suggest
>>>> something about the foundry_id field.
>>>
>>> This one seems more well-defined, so it's probably ok to add. What
>>> would be the use case of reading this? Would you want to read it
>>> just from user space or also from the kernel?
>>>
>>
>> As of now the use case I can think of, only involve reading this from user
>> space. For example for the same soc, coming from different foundries with
>> different manufacturing process, we may have a situation where some inconsistent
>> h/w behavior is being observed only on parts received from a certain foundry
>> and in those cases this information may help in segregation of problematic socs
>> and may also be used in testing these socs under a different set of settings like
>> voltage, frequency etc.
>>
>>> Maybe this can be combined with a manufacturing process, which probably
>>> falls into a similar category, so we could have something like
>>> "TSMC 28ULP" as a string in there.
>>>
>>
>> Yes. Having a manufacturing process as part of foundry-id can provide a more
>> thorough information.
> 
> Ok, sounds good. Let's do it like this. We can always add support for
> in-kernel matching of this string if needed later.
>

Thanks for the feedback. So how should I proceed now, should I 

i. send one patch first that adds the serial_number and foundry_id fields
in generic soc_dev_attribute structure and then send my modified socinfo 
driver as per new soc_dev_attribute structure

or 

ii. send both the changes as 2 separate patches of the same patch set.

or 

iii. Continue with the current soc_dev_attribute structure and modify
the socinfo driver once soc_dev_attribute structure has serial_number
and foundry_id fields.

 
> 	Arnd
> 


-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a\nmember of the Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply

* [PATCH 2/2] arm64: dts: rockchip: add usb2-phy otg-port support for rk3399
From: William Wu @ 2016-11-02  7:42 UTC (permalink / raw)
  To: kishon, heiko
  Cc: linux-kernel, linux-arm-kernel, linux-rockchip, devicetree,
	robh+dt, frank.wang, huangtao, dianders, briannorris, groeck,
	wulf
In-Reply-To: <1478072538-32081-1-git-send-email-wulf@rock-chips.com>

Add otg-port nodes for both u2phy0 and u2phy1. The otg-port can
be used for USB2.0 part of USB3.0 OTG controller.

Signed-off-by: William Wu <wulf@rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index b65c193..ea2df51 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1095,6 +1095,17 @@
 			clock-output-names = "clk_usbphy0_480m";
 			status = "disabled";
 
+			u2phy0_otg: otg-port {
+				#phy-cells = <0>;
+				interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH 0>;
+				interrupt-names = "otg-bvalid", "otg-id",
+						  "linestate";
+				status = "disabled";
+			};
+
+
 			u2phy0_host: host-port {
 				#phy-cells = <0>;
 				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
@@ -1112,6 +1123,16 @@
 			clock-output-names = "clk_usbphy1_480m";
 			status = "disabled";
 
+			u2phy1_otg: otg-port {
+				#phy-cells = <0>;
+				interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>,
+					     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH 0>;
+				interrupt-names = "otg-bvalid", "otg-id",
+						  "linestate";
+				status = "disabled";
+			};
+
 			u2phy1_host: host-port {
 				#phy-cells = <0>;
 				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH 0>;
-- 
2.0.0

^ permalink raw reply related

* [PATCH 1/2] phy: rockchip-inno-usb2: support otg-port for rk3399
From: William Wu @ 2016-11-02  7:42 UTC (permalink / raw)
  To: kishon, heiko
  Cc: linux-kernel, linux-arm-kernel, linux-rockchip, devicetree,
	robh+dt, frank.wang, huangtao, dianders, briannorris, groeck,
	wulf
In-Reply-To: <1478072538-32081-1-git-send-email-wulf@rock-chips.com>

The rk3399 SoC USB2 PHY is comprised of one Host port and
one OTG port. And OTG port is for USB2.0 part of USB3.0 OTG
controller, as a part to construct a fully feature Type-C
subsystem.

With this patch, we can support OTG port with the following
functions:
- Support BC1.2 charger detect, and use extcon notifier to
  send USB charger types to power driver.
- Support PHY suspend for power management.
- Support OTG Host only mode.
- Hold a wakelock when work as SDP(e.g. connect to PC).

Also, correct 480MHz output clock stable time. We found that
the system crashed due to 480MHz output clock of USB2 PHY was
unstable after clock had been enabled by gpu module.

Theoretically, 1 millisecond is a critical value for 480 output
clock stable time, so we try changing the delay time to 1.2
millisecond to avoid this issue.

Signed-off-by: William Wu <wulf@rock-chips.com>
---
 drivers/phy/phy-rockchip-inno-usb2.c | 609 +++++++++++++++++++++++++++++++++--
 1 file changed, 578 insertions(+), 31 deletions(-)

diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
index ac20310..352cf87 100644
--- a/drivers/phy/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/phy-rockchip-inno-usb2.c
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/extcon.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/gpio/consumer.h>
@@ -30,11 +31,16 @@
 #include <linux/of_platform.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/power_supply.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include <linux/wakelock.h>
 
 #define BIT_WRITEABLE_SHIFT	16
-#define SCHEDULE_DELAY	(60 * HZ)
+#define SCHEDULE_DELAY		(60 * HZ)
+#define OTG_SCHEDULE_DELAY	(2 * HZ)
 
 enum rockchip_usb2phy_port_id {
 	USB2PHY_PORT_OTG,
@@ -49,6 +55,37 @@ enum rockchip_usb2phy_host_state {
 	PHY_STATE_FS_LS_ONLINE	= 4,
 };
 
+/**
+ * Different states involved in USB charger detection.
+ * USB_CHG_STATE_UNDEFINED	USB charger is not connected or detection
+ *				process is not yet started.
+ * USB_CHG_STATE_WAIT_FOR_DCD	Waiting for Data pins contact.
+ * USB_CHG_STATE_DCD_DONE	Data pin contact is detected.
+ * USB_CHG_STATE_PRIMARY_DONE	Primary detection is completed (Detects
+ *				between SDP and DCP/CDP).
+ * USB_CHG_STATE_SECONDARY_DONE	Secondary detection is completed (Detects
+ *				between DCP and CDP).
+ * USB_CHG_STATE_DETECTED	USB charger type is determined.
+ */
+enum usb_chg_state {
+	USB_CHG_STATE_UNDEFINED = 0,
+	USB_CHG_STATE_WAIT_FOR_DCD,
+	USB_CHG_STATE_DCD_DONE,
+	USB_CHG_STATE_PRIMARY_DONE,
+	USB_CHG_STATE_SECONDARY_DONE,
+	USB_CHG_STATE_DETECTED,
+};
+
+static const unsigned int rockchip_usb2phy_extcon_cable[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_CHG_USB_SDP,
+	EXTCON_CHG_USB_CDP,
+	EXTCON_CHG_USB_DCP,
+	EXTCON_CHG_USB_SLOW,
+	EXTCON_NONE,
+};
+
 struct usb2phy_reg {
 	unsigned int	offset;
 	unsigned int	bitend;
@@ -58,19 +95,55 @@ struct usb2phy_reg {
 };
 
 /**
+ * struct rockchip_chg_det_reg: usb charger detect registers
+ * @cp_det: charging port detected successfully.
+ * @dcp_det: dedicated charging port detected successfully.
+ * @dp_det: assert data pin connect successfully.
+ * @idm_sink_en: open dm sink curren.
+ * @idp_sink_en: open dp sink current.
+ * @idp_src_en: open dm source current.
+ * @rdm_pdwn_en: open dm pull down resistor.
+ * @vdm_src_en: open dm voltage source.
+ * @vdp_src_en: open dp voltage source.
+ * @opmode: utmi operational mode.
+ */
+struct rockchip_chg_det_reg {
+	struct usb2phy_reg	cp_det;
+	struct usb2phy_reg	dcp_det;
+	struct usb2phy_reg	dp_det;
+	struct usb2phy_reg	idm_sink_en;
+	struct usb2phy_reg	idp_sink_en;
+	struct usb2phy_reg	idp_src_en;
+	struct usb2phy_reg	rdm_pdwn_en;
+	struct usb2phy_reg	vdm_src_en;
+	struct usb2phy_reg	vdp_src_en;
+	struct usb2phy_reg	opmode;
+};
+
+/**
  * struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
  * @phy_sus: phy suspend register.
+ * @bvalid_det_en: vbus valid rise detection enable register.
+ * @bvalid_det_st: vbus valid rise detection status register.
+ * @bvalid_det_clr: vbus valid rise detection clear register.
  * @ls_det_en: linestate detection enable register.
  * @ls_det_st: linestate detection state register.
  * @ls_det_clr: linestate detection clear register.
+ * @utmi_avalid: utmi vbus avalid status register.
+ * @utmi_bvalid: utmi vbus bvalid status register.
  * @utmi_ls: utmi linestate state register.
  * @utmi_hstdet: utmi host disconnect register.
  */
 struct rockchip_usb2phy_port_cfg {
 	struct usb2phy_reg	phy_sus;
+	struct usb2phy_reg	bvalid_det_en;
+	struct usb2phy_reg	bvalid_det_st;
+	struct usb2phy_reg	bvalid_det_clr;
 	struct usb2phy_reg	ls_det_en;
 	struct usb2phy_reg	ls_det_st;
 	struct usb2phy_reg	ls_det_clr;
+	struct usb2phy_reg	utmi_avalid;
+	struct usb2phy_reg	utmi_bvalid;
 	struct usb2phy_reg	utmi_ls;
 	struct usb2phy_reg	utmi_hstdet;
 };
@@ -80,31 +153,54 @@ struct rockchip_usb2phy_port_cfg {
  * @reg: the address offset of grf for usb-phy config.
  * @num_ports: specify how many ports that the phy has.
  * @clkout_ctl: keep on/turn off output clk of phy.
+ * @chg_det: charger detection registers.
  */
 struct rockchip_usb2phy_cfg {
 	unsigned int	reg;
 	unsigned int	num_ports;
 	struct usb2phy_reg	clkout_ctl;
 	const struct rockchip_usb2phy_port_cfg	port_cfgs[USB2PHY_NUM_PORTS];
+	const struct rockchip_chg_det_reg	chg_det;
 };
 
 /**
  * struct rockchip_usb2phy_port: usb-phy port data.
  * @port_id: flag for otg port or host port.
  * @suspended: phy suspended flag.
+ * @utmi_avalid: utmi avalid status usage flag.
+ *	true	- use avalid to get vbus status
+ *	flase	- use bvalid to get vbus status
+ * @vbus_attached: otg device vbus status.
+ * @bvalid_irq: IRQ number assigned for vbus valid rise detection.
  * @ls_irq: IRQ number assigned for linestate detection.
  * @mutex: for register updating in sm_work.
- * @sm_work: OTG state machine work.
+ * @chg_work: charge detect work.
+ * @otg_sm_work: OTG state machine work.
+ * @sm_work: HOST state machine work.
  * @phy_cfg: port register configuration, assigned by driver data.
+ * @event_nb: hold event notification callback.
+ * @wakelock: wake lock struct to prevent system suspend
+ *	      when USB is active.
+ * @state: define OTG enumeration states before device reset.
+ * @mode: the dr_mode of the controller.
  */
 struct rockchip_usb2phy_port {
 	struct phy	*phy;
 	unsigned int	port_id;
 	bool		suspended;
+	bool		utmi_avalid;
+	bool		vbus_attached;
+	int		bvalid_irq;
 	int		ls_irq;
 	struct mutex	mutex;
+	struct		delayed_work chg_work;
+	struct		delayed_work otg_sm_work;
 	struct		delayed_work sm_work;
 	const struct	rockchip_usb2phy_port_cfg *port_cfg;
+	struct notifier_block	event_nb;
+	struct wake_lock	wakelock;
+	enum usb_otg_state	state;
+	enum usb_dr_mode	mode;
 };
 
 /**
@@ -113,6 +209,11 @@ struct rockchip_usb2phy_port {
  * @clk: clock struct of phy input clk.
  * @clk480m: clock struct of phy output clk.
  * @clk_hw: clock struct of phy output clk management.
+ * @chg_state: states involved in USB charger detection.
+ * @chg_type: USB charger types.
+ * @dcd_retries: The retry count used to track Data contact
+ *		 detection process.
+ * @edev: extcon device for notification registration
  * @phy_cfg: phy register configuration, assigned by driver data.
  * @ports: phy port instance.
  */
@@ -122,6 +223,10 @@ struct rockchip_usb2phy {
 	struct clk	*clk;
 	struct clk	*clk480m;
 	struct clk_hw	clk480m_hw;
+	enum usb_chg_state	chg_state;
+	enum power_supply_type	chg_type;
+	u8			dcd_retries;
+	struct extcon_dev	*edev;
 	const struct rockchip_usb2phy_cfg	*phy_cfg;
 	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
 };
@@ -166,7 +271,7 @@ static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
 			return ret;
 
 		/* waitting for the clk become stable */
-		mdelay(1);
+		udelay(1200);
 	}
 
 	return 0;
@@ -263,33 +368,84 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy)
 	return ret;
 }
 
-static int rockchip_usb2phy_init(struct phy *phy)
+static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy)
 {
-	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
-	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
 	int ret;
+	struct device_node *node = rphy->dev->of_node;
+	struct extcon_dev *edev;
+
+	if (of_property_read_bool(node, "extcon")) {
+		edev = extcon_get_edev_by_phandle(rphy->dev, 0);
+		if (IS_ERR(edev)) {
+			if (PTR_ERR(edev) != -EPROBE_DEFER)
+				dev_err(rphy->dev, "Invalid or missing extcon\n");
+			return PTR_ERR(edev);
+		}
+	} else {
+		/* Initialize extcon device */
+		edev = devm_extcon_dev_allocate(rphy->dev,
+						rockchip_usb2phy_extcon_cable);
 
-	if (rport->port_id == USB2PHY_PORT_HOST) {
-		/* clear linestate and enable linestate detect irq */
-		mutex_lock(&rport->mutex);
+		if (IS_ERR(edev))
+			return -ENOMEM;
 
-		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		ret = devm_extcon_dev_register(rphy->dev, edev);
 		if (ret) {
-			mutex_unlock(&rport->mutex);
+			dev_err(rphy->dev, "failed to register extcon device\n");
 			return ret;
 		}
+	}
 
-		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
-		if (ret) {
-			mutex_unlock(&rport->mutex);
-			return ret;
+	rphy->edev = edev;
+
+	return 0;
+}
+
+static int rockchip_usb2phy_init(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret = 0;
+
+	mutex_lock(&rport->mutex);
+
+	if (rport->port_id == USB2PHY_PORT_OTG) {
+		if (rport->mode != USB_DR_MODE_HOST) {
+			/* clear bvalid status and enable bvalid detect irq */
+			ret = property_enable(rphy,
+					      &rport->port_cfg->bvalid_det_clr,
+					      true);
+			if (ret)
+				goto out;
+
+			ret = property_enable(rphy,
+					      &rport->port_cfg->bvalid_det_en,
+					      true);
+			if (ret)
+				goto out;
+
+			schedule_delayed_work(&rport->otg_sm_work,
+					      OTG_SCHEDULE_DELAY);
+		} else {
+			/* If OTG works in host only mode, do nothing. */
+			dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode);
 		}
+	} else if (rport->port_id == USB2PHY_PORT_HOST) {
+		/* clear linestate and enable linestate detect irq */
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		if (ret)
+			goto out;
+
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
+		if (ret)
+			goto out;
 
-		mutex_unlock(&rport->mutex);
 		schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
 	}
 
-	return 0;
+out:
+	mutex_unlock(&rport->mutex);
+	return ret;
 }
 
 static int rockchip_usb2phy_power_on(struct phy *phy)
@@ -340,7 +496,19 @@ static int rockchip_usb2phy_exit(struct phy *phy)
 {
 	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
 
-	if (rport->port_id == USB2PHY_PORT_HOST)
+	if (rport->port_id == USB2PHY_PORT_OTG &&
+	    rport->mode != USB_DR_MODE_HOST)
+		/*
+		 * Don't cancel otg_sm_work when phy exit, because
+		 * the otg_sm_work is a OTG state machine delay work,
+		 * it will hold a wake lock if SDP cable or CDP cable
+		 * is attached, and release the wake lock if cable
+		 * dettached. If usb controller(e.g. DWC3) call phy exit
+		 * when USB cable is dettached and cancel otg_sm_work,
+		 * it may cause the usb phy keeping hold of wake lock
+		 */
+		cancel_delayed_work_sync(&rport->chg_work);
+	else if (rport->port_id == USB2PHY_PORT_HOST)
 		cancel_delayed_work_sync(&rport->sm_work);
 
 	return 0;
@@ -354,6 +522,252 @@ static const struct phy_ops rockchip_usb2phy_ops = {
 	.owner		= THIS_MODULE,
 };
 
+static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(work, struct rockchip_usb2phy_port,
+			     otg_sm_work.work);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+	static unsigned int cable;
+	unsigned long delay;
+	bool vbus_attach, sch_work, notify_charger;
+
+	if (rport->utmi_avalid)
+		vbus_attach =
+			property_enabled(rphy, &rport->port_cfg->utmi_avalid);
+	else
+		vbus_attach =
+			property_enabled(rphy, &rport->port_cfg->utmi_bvalid);
+
+	sch_work = false;
+	notify_charger = false;
+	delay = OTG_SCHEDULE_DELAY;
+	dev_dbg(&rport->phy->dev, "%s otg sm work\n",
+		usb_otg_state_string(rport->state));
+
+	switch (rport->state) {
+	case OTG_STATE_UNDEFINED:
+		rport->state = OTG_STATE_B_IDLE;
+		if (!vbus_attach)
+			rockchip_usb2phy_power_off(rport->phy);
+		/* fall through */
+	case OTG_STATE_B_IDLE:
+		if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) > 0) {
+			dev_dbg(&rport->phy->dev, "usb otg host connect\n");
+			rport->state = OTG_STATE_A_HOST;
+			rockchip_usb2phy_power_on(rport->phy);
+			return;
+		} else if (vbus_attach) {
+			dev_dbg(&rport->phy->dev, "vbus_attach\n");
+			switch (rphy->chg_state) {
+			case USB_CHG_STATE_UNDEFINED:
+				schedule_delayed_work(&rport->chg_work, 0);
+				return;
+			case USB_CHG_STATE_DETECTED:
+				switch (rphy->chg_type) {
+				case POWER_SUPPLY_TYPE_USB:
+					dev_dbg(&rport->phy->dev,
+						"sdp cable is connecetd\n");
+					wake_lock(&rport->wakelock);
+					rockchip_usb2phy_power_on(rport->phy);
+					rport->state = OTG_STATE_B_PERIPHERAL;
+					notify_charger = true;
+					sch_work = true;
+					cable = EXTCON_CHG_USB_SDP;
+					break;
+				case POWER_SUPPLY_TYPE_USB_DCP:
+					dev_dbg(&rport->phy->dev,
+						"dcp cable is connecetd\n");
+					rockchip_usb2phy_power_off(rport->phy);
+					notify_charger = true;
+					sch_work = true;
+					cable = EXTCON_CHG_USB_DCP;
+					break;
+				case POWER_SUPPLY_TYPE_USB_CDP:
+					dev_dbg(&rport->phy->dev,
+						"cdp cable is connecetd\n");
+					wake_lock(&rport->wakelock);
+					rockchip_usb2phy_power_on(rport->phy);
+					rport->state = OTG_STATE_B_PERIPHERAL;
+					notify_charger = true;
+					sch_work = true;
+					cable = EXTCON_CHG_USB_CDP;
+					break;
+				default:
+					break;
+				}
+				break;
+			default:
+				break;
+			}
+		} else {
+			notify_charger = true;
+			rphy->chg_state = USB_CHG_STATE_UNDEFINED;
+			rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
+		}
+
+		if (rport->vbus_attached != vbus_attach) {
+			rport->vbus_attached = vbus_attach;
+
+			if (notify_charger && rphy->edev)
+				extcon_set_cable_state_(rphy->edev,
+							cable, vbus_attach);
+		}
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!vbus_attach) {
+			dev_dbg(&rport->phy->dev, "usb disconnect\n");
+			rphy->chg_state = USB_CHG_STATE_UNDEFINED;
+			rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
+			rport->state = OTG_STATE_B_IDLE;
+			delay = 0;
+			rockchip_usb2phy_power_off(rport->phy);
+			wake_unlock(&rport->wakelock);
+		}
+		sch_work = true;
+		break;
+	case OTG_STATE_A_HOST:
+		if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) == 0) {
+			dev_dbg(&rport->phy->dev, "usb otg host disconnect\n");
+			rport->state = OTG_STATE_B_IDLE;
+			rockchip_usb2phy_power_off(rport->phy);
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (sch_work)
+		schedule_delayed_work(&rport->otg_sm_work, delay);
+}
+
+static const char *chg_to_string(enum power_supply_type chg_type)
+{
+	switch (chg_type) {
+	case POWER_SUPPLY_TYPE_USB:
+		return "USB_SDP_CHARGER";
+	case POWER_SUPPLY_TYPE_USB_DCP:
+		return "USB_DCP_CHARGER";
+	case POWER_SUPPLY_TYPE_USB_CDP:
+		return "USB_CDP_CHARGER";
+	default:
+		return "INVALID_CHARGER";
+	}
+}
+
+static void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy,
+				    bool en)
+{
+	property_enable(rphy, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en);
+	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_src_en, en);
+}
+
+static void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy,
+					    bool en)
+{
+	property_enable(rphy, &rphy->phy_cfg->chg_det.vdp_src_en, en);
+	property_enable(rphy, &rphy->phy_cfg->chg_det.idm_sink_en, en);
+}
+
+static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy,
+					      bool en)
+{
+	property_enable(rphy, &rphy->phy_cfg->chg_det.vdm_src_en, en);
+	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_sink_en, en);
+}
+
+#define CHG_DCD_POLL_TIME	(100 * HZ / 1000)
+#define CHG_DCD_MAX_RETRIES	6
+#define CHG_PRIMARY_DET_TIME	(40 * HZ / 1000)
+#define CHG_SECONDARY_DET_TIME	(40 * HZ / 1000)
+static void rockchip_chg_detect_work(struct work_struct *work)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(work, struct rockchip_usb2phy_port, chg_work.work);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+	bool is_dcd, tmout, vout;
+	unsigned long delay;
+
+	dev_dbg(&rport->phy->dev, "chg detection work state = %d\n",
+		rphy->chg_state);
+	switch (rphy->chg_state) {
+	case USB_CHG_STATE_UNDEFINED:
+		if (!rport->suspended)
+			rockchip_usb2phy_power_off(rport->phy);
+		/* put the controller in non-driving mode */
+		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, false);
+		/* Start DCD processing stage 1 */
+		rockchip_chg_enable_dcd(rphy, true);
+		rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
+		rphy->dcd_retries = 0;
+		delay = CHG_DCD_POLL_TIME;
+		break;
+	case USB_CHG_STATE_WAIT_FOR_DCD:
+		/* get data contact detection status */
+		is_dcd = property_enabled(rphy, &rphy->phy_cfg->chg_det.dp_det);
+		tmout = ++rphy->dcd_retries == CHG_DCD_MAX_RETRIES;
+		/* stage 2 */
+		if (is_dcd || tmout) {
+			/* stage 4 */
+			/* Turn off DCD circuitry */
+			rockchip_chg_enable_dcd(rphy, false);
+			/* Voltage Source on DP, Probe on DM */
+			rockchip_chg_enable_primary_det(rphy, true);
+			delay = CHG_PRIMARY_DET_TIME;
+			rphy->chg_state = USB_CHG_STATE_DCD_DONE;
+		} else {
+			/* stage 3 */
+			delay = CHG_DCD_POLL_TIME;
+		}
+		break;
+	case USB_CHG_STATE_DCD_DONE:
+		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.cp_det);
+		rockchip_chg_enable_primary_det(rphy, false);
+		if (vout) {
+			/* Voltage Source on DM, Probe on DP  */
+			rockchip_chg_enable_secondary_det(rphy, true);
+			delay = CHG_SECONDARY_DET_TIME;
+			rphy->chg_state = USB_CHG_STATE_PRIMARY_DONE;
+		} else {
+			if (tmout) {
+				/* floating charger found */
+				rphy->chg_type = POWER_SUPPLY_TYPE_USB_DCP;
+				rphy->chg_state = USB_CHG_STATE_DETECTED;
+				delay = 0;
+			} else {
+				rphy->chg_type = POWER_SUPPLY_TYPE_USB;
+				rphy->chg_state = USB_CHG_STATE_DETECTED;
+				delay = 0;
+			}
+		}
+		break;
+	case USB_CHG_STATE_PRIMARY_DONE:
+		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.dcp_det);
+		/* Turn off voltage source */
+		rockchip_chg_enable_secondary_det(rphy, false);
+		if (vout)
+			rphy->chg_type = POWER_SUPPLY_TYPE_USB_DCP;
+		else
+			rphy->chg_type = POWER_SUPPLY_TYPE_USB_CDP;
+		/* fall through */
+	case USB_CHG_STATE_SECONDARY_DONE:
+		rphy->chg_state = USB_CHG_STATE_DETECTED;
+		delay = 0;
+		/* fall through */
+	case USB_CHG_STATE_DETECTED:
+		/* put the controller in normal mode */
+		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, true);
+		rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
+		dev_info(&rport->phy->dev, "charger = %s\n",
+			 chg_to_string(rphy->chg_type));
+		return;
+	default:
+		return;
+	}
+
+	schedule_delayed_work(&rport->chg_work, delay);
+}
+
 /*
  * The function manage host-phy port state and suspend/resume phy port
  * to save power.
@@ -485,6 +899,26 @@ static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data)
+{
+	struct rockchip_usb2phy_port *rport = data;
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+
+	if (!property_enabled(rphy, &rport->port_cfg->bvalid_det_st))
+		return IRQ_NONE;
+
+	mutex_lock(&rport->mutex);
+
+	/* clear bvalid detect irq pending status */
+	property_enable(rphy, &rport->port_cfg->bvalid_det_clr, true);
+
+	mutex_unlock(&rport->mutex);
+
+	rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
+
+	return IRQ_HANDLED;
+}
+
 static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
 					   struct rockchip_usb2phy_port *rport,
 					   struct device_node *child_np)
@@ -509,13 +943,87 @@ static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
 					IRQF_ONESHOT,
 					"rockchip_usb2phy", rport);
 	if (ret) {
-		dev_err(rphy->dev, "failed to request irq handle\n");
+		dev_err(rphy->dev, "failed to request linestate irq handle\n");
 		return ret;
 	}
 
 	return 0;
 }
 
+static int rockchip_otg_event(struct notifier_block *nb,
+			      unsigned long event, void *ptr)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(nb, struct rockchip_usb2phy_port, event_nb);
+
+	schedule_delayed_work(&rport->otg_sm_work, OTG_SCHEDULE_DELAY);
+
+	return NOTIFY_DONE;
+}
+
+static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
+					  struct rockchip_usb2phy_port *rport,
+					  struct device_node *child_np)
+{
+	int ret;
+
+	rport->port_id = USB2PHY_PORT_OTG;
+	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
+	rport->state = OTG_STATE_UNDEFINED;
+
+	/*
+	 * set suspended flag to true, but actually don't
+	 * put phy in suspend mode, it aims to enable usb
+	 * phy and clock in power_on() called by usb controller
+	 * driver during probe.
+	 */
+	rport->suspended = true;
+	rport->vbus_attached = false;
+
+	mutex_init(&rport->mutex);
+
+	rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1);
+	if (rport->mode == USB_DR_MODE_HOST) {
+		ret = 0;
+		goto out;
+	}
+
+	wake_lock_init(&rport->wakelock, WAKE_LOCK_SUSPEND, "rockchip_otg");
+	INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
+	INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
+
+	rport->utmi_avalid =
+		of_property_read_bool(child_np, "rockchip,utmi-avalid");
+
+	rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid");
+	if (rport->bvalid_irq < 0) {
+		dev_err(rphy->dev, "no vbus valid irq provided\n");
+		ret = rport->bvalid_irq;
+		goto out;
+	}
+
+	ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq, NULL,
+					rockchip_usb2phy_bvalid_irq,
+					IRQF_ONESHOT,
+					"rockchip_usb2phy_bvalid", rport);
+	if (ret) {
+		dev_err(rphy->dev, "failed to request otg-bvalid irq handle\n");
+		goto out;
+	}
+
+	if (!IS_ERR(rphy->edev)) {
+		rport->event_nb.notifier_call = rockchip_otg_event;
+
+		ret = extcon_register_notifier(rphy->edev, EXTCON_USB_HOST,
+					       &rport->event_nb);
+		if (ret)
+			dev_err(rphy->dev, "register USB HOST notifier failed\n");
+	}
+
+out:
+	return ret;
+}
+
 static int rockchip_usb2phy_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -553,8 +1061,14 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 
 	rphy->dev = dev;
 	phy_cfgs = match->data;
+	rphy->chg_state = USB_CHG_STATE_UNDEFINED;
+	rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
 	platform_set_drvdata(pdev, rphy);
 
+	ret = rockchip_usb2phy_extcon_register(rphy);
+	if (ret)
+		return ret;
+
 	/* find out a proper config which can be matched with dt. */
 	index = 0;
 	while (phy_cfgs[index].reg) {
@@ -591,13 +1105,9 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 		struct rockchip_usb2phy_port *rport = &rphy->ports[index];
 		struct phy *phy;
 
-		/*
-		 * This driver aim to support both otg-port and host-port,
-		 * but unfortunately, the otg part is not ready in current,
-		 * so this comments and below codes are interim, which should
-		 * be changed after otg-port is supplied soon.
-		 */
-		if (of_node_cmp(child_np->name, "host-port"))
+		/* This driver aims to support both otg-port and host-port */
+		if (of_node_cmp(child_np->name, "host-port") &&
+		    of_node_cmp(child_np->name, "otg-port"))
 			goto next_child;
 
 		phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops);
@@ -610,9 +1120,18 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 		rport->phy = phy;
 		phy_set_drvdata(rport->phy, rport);
 
-		ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np);
-		if (ret)
-			goto put_child;
+		/* initialize otg/host port separately */
+		if (!of_node_cmp(child_np->name, "host-port")) {
+			ret = rockchip_usb2phy_host_port_init(rphy, rport,
+							      child_np);
+			if (ret)
+				goto put_child;
+		} else {
+			ret = rockchip_usb2phy_otg_port_init(rphy, rport,
+							     child_np);
+			if (ret)
+				goto put_child;
+		}
 
 next_child:
 		/* to prevent out of boundary */
@@ -654,10 +1173,18 @@ static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
 
 static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
 	{
-		.reg = 0xe450,
+		.reg		= 0xe450,
 		.num_ports	= 2,
 		.clkout_ctl	= { 0xe450, 4, 4, 1, 0 },
 		.port_cfgs	= {
+			[USB2PHY_PORT_OTG] = {
+				.phy_sus	= { 0xe454, 1, 0, 2, 1 },
+				.bvalid_det_en	= { 0xe3c0, 3, 3, 0, 1 },
+				.bvalid_det_st	= { 0xe3e0, 3, 3, 0, 1 },
+				.bvalid_det_clr	= { 0xe3d0, 3, 3, 0, 1 },
+				.utmi_avalid	= { 0xe2ac, 7, 7, 0, 1 },
+				.utmi_bvalid	= { 0xe2ac, 12, 12, 0, 1 },
+			},
 			[USB2PHY_PORT_HOST] = {
 				.phy_sus	= { 0xe458, 1, 0, 0x2, 0x1 },
 				.ls_det_en	= { 0xe3c0, 6, 6, 0, 1 },
@@ -667,12 +1194,32 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
 				.utmi_hstdet	= { 0xe2ac, 23, 23, 0, 1 }
 			}
 		},
+		.chg_det = {
+			.opmode		= { 0xe454, 3, 0, 5, 1 },
+			.cp_det		= { 0xe2ac, 2, 2, 0, 1 },
+			.dcp_det	= { 0xe2ac, 1, 1, 0, 1 },
+			.dp_det		= { 0xe2ac, 0, 0, 0, 1 },
+			.idm_sink_en	= { 0xe450, 8, 8, 0, 1 },
+			.idp_sink_en	= { 0xe450, 7, 7, 0, 1 },
+			.idp_src_en	= { 0xe450, 9, 9, 0, 1 },
+			.rdm_pdwn_en	= { 0xe450, 10, 10, 0, 1 },
+			.vdm_src_en	= { 0xe450, 12, 12, 0, 1 },
+			.vdp_src_en	= { 0xe450, 11, 11, 0, 1 },
+		},
 	},
 	{
-		.reg = 0xe460,
+		.reg		= 0xe460,
 		.num_ports	= 2,
 		.clkout_ctl	= { 0xe460, 4, 4, 1, 0 },
 		.port_cfgs	= {
+			[USB2PHY_PORT_OTG] = {
+				.phy_sus        = { 0xe464, 1, 0, 2, 1 },
+				.bvalid_det_en  = { 0xe3c0, 8, 8, 0, 1 },
+				.bvalid_det_st  = { 0xe3e0, 8, 8, 0, 1 },
+				.bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },
+				.utmi_avalid	= { 0xe2ac, 10, 10, 0, 1 },
+				.utmi_bvalid    = { 0xe2ac, 16, 16, 0, 1 },
+			},
 			[USB2PHY_PORT_HOST] = {
 				.phy_sus	= { 0xe468, 1, 0, 0x2, 0x1 },
 				.ls_det_en	= { 0xe3c0, 11, 11, 0, 1 },
-- 
2.0.0

^ permalink raw reply related

* [PATCH 0/2] support USB2 PHY OTG port for rk3399
From: William Wu @ 2016-11-02  7:42 UTC (permalink / raw)
  To: kishon, heiko
  Cc: linux-kernel, linux-arm-kernel, linux-rockchip, devicetree,
	robh+dt, frank.wang, huangtao, dianders, briannorris, groeck,
	wulf

This series add support for rk3399 USB2 PHY0 and PHY1 OTG port.
rk3399 has two USB2 PHYs, and each USB2 PHY is comprised of one
Host port and one OTG port. We have supported Host port before,
and try to support OTG port now.

Test on rk3399-evb board.

William Wu (2):
  phy: rockchip-inno-usb2: support otg-port for rk3399
  arm64: dts: rockchip: add usb2-phy otg-port support for rk3399

 arch/arm64/boot/dts/rockchip/rk3399.dtsi |  21 ++
 drivers/phy/phy-rockchip-inno-usb2.c     | 609 +++++++++++++++++++++++++++++--
 2 files changed, 599 insertions(+), 31 deletions(-)

-- 
2.0.0

^ 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