* [PATCH v27 9/9] Documentation: dt: chosen properties for arm64 kdump
From: AKASHI Takahiro @ 2016-11-02 4:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161102044959.11954-1-takahiro.akashi@linaro.org>
From: James Morse <james.morse@arm.com>
Add documentation for
linux,crashkernel-base and crashkernel-size,
linux,usable-memory-range
linux,elfcorehdr
used by arm64 kdump to decribe the kdump reserved area, and
the elfcorehdr's location within it.
Signed-off-by: James Morse <james.morse@arm.com>
[takahiro.akashi at linaro.org: added "linux,crashkernel-base" and "-size" ]
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: devicetree at vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
---
Documentation/devicetree/bindings/chosen.txt | 50 ++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt
index 6ae9d82..7b11516 100644
--- a/Documentation/devicetree/bindings/chosen.txt
+++ b/Documentation/devicetree/bindings/chosen.txt
@@ -52,3 +52,53 @@ This property is set (currently only on PowerPC, and only needed on
book3e) by some versions of kexec-tools to tell the new kernel that it
is being booted by kexec, as the booting environment may differ (e.g.
a different secondary CPU release mechanism)
+
+linux,crashkernel-base
+linux,crashkernel-size
+----------------------
+
+These properties (currently used on PowerPC and arm64) indicates
+the base address and the size, respectively, of the reserved memory
+range for crash dump kernel.
+e.g.
+
+/ {
+ chosen {
+ linux,crashkernel-base = <0x9 0xf0000000>;
+ linux,crashkernel-size = <0x0 0x10000000>;
+ };
+};
+
+linux,usable-memory-range
+-------------------------
+
+This property (currently used only on arm64) holds the memory range,
+the base address and the size, which can be used as system ram on
+the *current* kernel. Note that, if this property is present, any memory
+regions under "memory" nodes in DT blob or ones marked as "conventional
+memory" in EFI memory map should be ignored.
+e.g.
+
+/ {
+ chosen {
+ linux,usable-memory-range = <0x9 0xf0000000 0x0 0x10000000>;
+ };
+};
+
+The main usage is for crash dump kernel to identify its own usable
+memory and exclude, at its boot time, any other memory areas that are
+part of the panicked kernel's memory.
+
+linux,elfcorehdr
+----------------
+
+This property (currently used only on arm64) holds the memory range,
+the address and the size, of the elf core header which mainly describes
+the panicked kernel's memory layout as PT_LOAD segments of elf format.
+e.g.
+
+/ {
+ chosen {
+ linux,elfcorehdr = <0x9 0xfffff000 0x0 0x800>;
+ };
+};
--
2.10.0
^ permalink raw reply related
* [PATCH v2] ARM: at91/dt: add dts file for sama5d36ek CMP board
From: kbuild test robot @ 2016-11-02 5:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478055958-8463-1-git-send-email-wenyou.yang@atmel.com>
Hi Wenyou,
[auto build test ERROR on at91/at91-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]
url: https://github.com/0day-ci/linux/commits/Wenyou-Yang/ARM-at91-dt-add-dts-file-for-sama5d36ek-CMP-board/20161102-111152
base: https://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git at91-next
config: arm-at91_dt_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
All errors (new ones prefixed by >>):
>> Error: arch/arm/boot/dts/sama5d3xmb_cmp.dtsi:143.17-18 syntax error
FATAL ERROR: Unable to parse input tree
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 21326 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161102/e70be8e1/attachment-0001.gz>
^ permalink raw reply
* [PATCH v2 4/9] regulator: lp873x: Add support for populating input supply
From: Lokesh Vutla @ 2016-11-02 5:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161030204118.ojeetnxl5qsi6lp7@rob-hp-laptop>
On Monday 31 October 2016 02:11 AM, Rob Herring wrote:
> On Fri, Oct 21, 2016 at 04:08:36PM +0530, Lokesh Vutla wrote:
>> In order to have a proper topology of regulators for a platform, each
>> registering regulator needs to populate supply_name field for identifying
>> its supply's name. Add supply_name field for lp873x regulators.
>>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Keerthy <j-keerthy@ti.com>
>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>> ---
>> Documentation/devicetree/bindings/mfd/lp873x.txt | 8 ++++++++
>> drivers/regulator/lp873x-regulator.c | 1 +
>> 2 files changed, 9 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/lp873x.txt b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> index 52766c2..998837a 100644
>> --- a/Documentation/devicetree/bindings/mfd/lp873x.txt
>> +++ b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> @@ -7,6 +7,9 @@ Required properties:
>> - #gpio-cells: Should be two. The first cell is the pin number and
>> the second cell is used to specify flags.
>> See ../gpio/gpio.txt for more information.
>> + - xxx-in-supply: Phandle to parent supply node of each regulator
>> + populated under regulators node. xxx should match
>> + the supply_name populated in driver.
>
> The driver is irrelevant. This should reference a list in this document.
okay. See if the below updated patch is fine.
-----------------------------8<----------------------------8<----------------------------
>From 666f925423fa35c7bfcc77fa3c883cbea5d8ef8e Mon Sep 17 00:00:00 2001
From: Lokesh Vutla <lokeshvutla@ti.com>
Date: Wed, 21 Sep 2016 11:50:49 +0530
Subject: [PATCH v3] regulator: lp873x: Add support for populating input
supply
In order to have a proper topology of regulators for a platform, each
registering regulator needs to populate supply_name field for identifying
its supply's name. Add supply_name field for lp873x regulators.
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
---
Documentation/devicetree/bindings/mfd/lp873x.txt | 8 ++++++++
drivers/regulator/lp873x-regulator.c | 1 +
2 files changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/lp873x.txt
b/Documentation/devicetree/bindings/mfd/lp873x.txt
index 52766c2..ae9cf39 100644
--- a/Documentation/devicetree/bindings/mfd/lp873x.txt
+++ b/Documentation/devicetree/bindings/mfd/lp873x.txt
@@ -7,6 +7,9 @@ Required properties:
- #gpio-cells: Should be two. The first cell is the pin number and
the second cell is used to specify flags.
See ../gpio/gpio.txt for more information.
+ - xxx-in-supply: Phandle to parent supply node of each regulator
+ populated under regulators node. xxx can be
+ buck0, buck1, ldo0 or ldo1.
- regulators: List of child nodes that specify the regulator
initialization data.
Example:
@@ -17,6 +20,11 @@ pmic: lp8733 at 60 {
gpio-controller;
#gpio-cells = <2>;
+ buck0-in-supply = <&vsys_3v3>;
+ buck1-in-supply = <&vsys_3v3>;
+ ldo0-in-supply = <&vsys_3v3>;
+ ldo1-in-supply = <&vsys_3v3>;
+
regulators {
lp8733_buck0: buck0 {
regulator-name = "lp8733-buck0";
diff --git a/drivers/regulator/lp873x-regulator.c
b/drivers/regulator/lp873x-regulator.c
index e504b91..70e3df6 100644
--- a/drivers/regulator/lp873x-regulator.c
+++ b/drivers/regulator/lp873x-regulator.c
@@ -24,6 +24,7 @@
[_id] = { \
.desc = { \
.name = _name, \
+ .supply_name = _of "-in", \
.id = _id, \
.of_match = of_match_ptr(_of), \
.regulators_node = of_match_ptr("regulators"),\
--
2.10.1
^ permalink raw reply related
* [PATCH v1] ARM:dmaengine:sun6i:fix the uninitialized value for v_lli
From: Axl-zhang @ 2016-11-02 5:31 UTC (permalink / raw)
To: linux-arm-kernel
dma_pool_alloc does not initialize the value of the newly allocated
block for the v_lli, and the uninitilize value make the tests failed
which is on pine64 with dmatest.
we can fix it just change the "|=" to "=" for the v_lli->cfg.
Signed-off-by: Hao Zhang <hao5781286@gmail.com>
---
drivers/dma/sun6i-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 3835fcd..52b48eb 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -578,7 +578,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
burst = convert_burst(8);
width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
- v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
+ v_lli->cfg = DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
DMA_CHAN_CFG_DST_LINEAR_MODE |
DMA_CHAN_CFG_SRC_LINEAR_MODE |
--
2.7.4
^ permalink raw reply related
* [PATCH v2] ARM: at91/dt: add dts file for sama5d36ek CMP board
From: Wenyou.Yang at microchip.com @ 2016-11-02 5:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201611021345.WcgqcfPD%fengguang.wu@intel.com>
> -----Original Message-----
> From: kbuild test robot [mailto:lkp at intel.com]
> Sent: 2016?11?2? 13:28
> To: Wenyou Yang - A41535 <Wenyou.Yang@microchip.com>
> Cc: kbuild-all at 01.org; Nicolas Ferre <nicolas.ferre@atmel.com>; Alexandre
> Belloni <alexandre.belloni@free-electrons.com>; Russell King
> <linux@arm.linux.org.uk>; Rob Herring <robh+dt@kernel.org>; Pawel Moll
> <pawel.moll@arm.com>; Mark Rutland <mark.rutland@arm.com>; Ian Campbell
> <ijc+devicetree@hellion.org.uk>; Kumar Gala <galak@codeaurora.org>; linux-
> kernel at vger.kernel.org; Wenyou Yang - A41535
> <Wenyou.Yang@microchip.com>; devicetree at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org; Wenyou Yang - A41535
> <Wenyou.Yang@microchip.com>
> Subject: Re: [PATCH v2] ARM: at91/dt: add dts file for sama5d36ek CMP board
>
> Hi Wenyou,
>
> [auto build test ERROR on at91/at91-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]
>
> url: https://github.com/0day-ci/linux/commits/Wenyou-Yang/ARM-at91-dt-add-
> dts-file-for-sama5d36ek-CMP-board/20161102-111152
> base: https://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git at91-
> next
> config: arm-at91_dt_defconfig (attached as .config)
> compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
> reproduce:
> wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-
> tests.git/plain/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=arm
>
> All errors (new ones prefixed by >>):
>
> >> Error: arch/arm/boot/dts/sama5d3xmb_cmp.dtsi:143.17-18 syntax error
> FATAL ERROR: Unable to parse input tree
Oh, this patch is based on the patch I sent before.
[PATCH] pinctrl: at91: add support for OUTPUT config
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-October/464354.html
I forgot adding this information.
Sorry.
Best Regards,
Wenyou Yang
^ permalink raw reply
* [PATCH 3/3] clk: imx: clk-imx6ul: add clk support for imx6ull
From: Peter Chen @ 2016-11-02 6:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161102001205.GA16026@codeaurora.org>
>
>On 11/01, Peter Chen wrote:
>> clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1",
> "usdhc1_podf", base + 0x80, 2);
>> clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2",
> "usdhc2_podf", base + 0x80, 4);
>> - clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1",
> "sim_sel", base + 0x80, 6);
>> - clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2",
> "sim_sel", base + 0x80, 8);
>> + if (clk_on_imx6ul()) {
>> + clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1",
> "sim_sel", base + 0x80, 6);
>> + clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2",
> "sim_sel", base + 0x80, 8);
>> + }
>> clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim",
> "eim_slow_podf", base + 0x80, 10);
>> clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8",
> "perclk", base + 0x80, 16);
>> clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg",
> base + 0x80, 14);
>> @@ -430,6 +478,7 @@ static void __init imx6ul_clocks_init(struct device_node
>*ccm_node)
>> clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000);
>> clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
>> clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
>> + clk_set_rate(clks[IMX6UL_CLK_PLL3_PFD2], 320000000);
>
>Can you use assigned clock rates for this instead?
>
Thanks, I will move it to dts.
Peter
^ permalink raw reply
* [PATCH] clk: rockchip: fix some clocks' name to be more standard style
From: Jianqun Xu @ 2016-11-02 7:04 UTC (permalink / raw)
To: linux-arm-kernel
Fix aclk_emmcgrf to aclk_emmc_grf, and fix aclk_emmccore to be
aclk_emmc_core.
Signed-off-by: Jianqun Xu <jay.xu@rock-chips.com>
---
drivers/clk/rockchip/clk-rk3399.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 2c7cba7..b3df2c6 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -935,11 +935,11 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
RK3399_CLKGATE_CON(6), 13, GFLAGS),
COMPOSITE_NOGATE(ACLK_EMMC, "aclk_emmc", mux_aclk_emmc_p, CLK_IGNORE_UNUSED,
RK3399_CLKSEL_CON(21), 7, 1, MFLAGS, 0, 5, DFLAGS),
- GATE(ACLK_EMMC_CORE, "aclk_emmccore", "aclk_emmc", CLK_IGNORE_UNUSED,
+ GATE(ACLK_EMMC_CORE, "aclk_emmc_core", "aclk_emmc", CLK_IGNORE_UNUSED,
RK3399_CLKGATE_CON(32), 8, GFLAGS),
GATE(ACLK_EMMC_NOC, "aclk_emmc_noc", "aclk_emmc", CLK_IGNORE_UNUSED,
RK3399_CLKGATE_CON(32), 9, GFLAGS),
- GATE(ACLK_EMMC_GRF, "aclk_emmcgrf", "aclk_emmc", CLK_IGNORE_UNUSED,
+ GATE(ACLK_EMMC_GRF, "aclk_emmc_grf", "aclk_emmc", CLK_IGNORE_UNUSED,
RK3399_CLKGATE_CON(32), 10, GFLAGS),
/* perilp0 */
--
1.9.1
^ permalink raw reply related
* [PATCH V3 4/8] drivers: platform: Configure dma operations at probe time
From: Sricharan @ 2016-11-02 7:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027104924.GA16905@red-moon>
Hi Lorenzo,
>-----Original Message-----
From: linux-arm-msm-owner@vger.kernel.org [mailto:linux-arm-msm-owner at vger.kernel.org] On Behalf Of Lorenzo Pieralisi
>Sent: Thursday, October 27, 2016 4:19 PM
>To: Sricharan <sricharan@codeaurora.org>
>Cc: 'Robin Murphy' <robin.murphy@arm.com>; will.deacon at arm.com; joro at 8bytes.org; iommu at lists.linux-foundation.org; linux-
>arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; laurent.pinchart at ideasonboard.com;
>m.szyprowski at samsung.com; tfiga at chromium.org; srinivas.kandagatla at linaro.org
>Subject: Re: [PATCH V3 4/8] drivers: platform: Configure dma operations at probe time
>
>On Wed, Oct 26, 2016 at 08:34:59PM +0530, Sricharan wrote:
>> Hi Robin,
>>
>> >On 04/10/16 18:03, Sricharan R wrote:
>> >> Configuring DMA ops at probe time will allow deferring device probe when
>> >> the IOMMU isn't available yet. The dma_configure for the device is now called
>> >> from the generic device_attach callback just before the bus/driver probe
>> >> is called. This way, configuring the dma ops for the device would be called
>> >> at the same place for all bus_types, hence the deferred probing mechanism
>> >> should work for all buses as well.
>> >>
>> >> pci_bus_add_devices (platform/amba)(_device_create/driver_register)
>> >> | |
>> >> pci_bus_add_device (device_add/driver_register)
>> >> | |
>> >> device_attach device_initial_probe
>> >> | |
>> >> __device_attach_driver __device_attach_driver
>> >> |
>> >> driver_probe_device
>> >> |
>> >> really_probe
>> >> |
>> >> dma_configure
>> >>
>> >> Similarly on the device/driver_unregister path __device_release_driver is
>> >> called which inturn calls dma_deconfigure.
>> >>
>> >> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> >> ---
>> >> drivers/base/dd.c | 10 ++++++++++
>> >> drivers/base/dma-mapping.c | 11 +++++++++++
>> >> drivers/of/platform.c | 4 ----
>> >> drivers/pci/probe.c | 5 +----
>> >> include/linux/dma-mapping.h | 3 +++
>> >> 5 files changed, 25 insertions(+), 8 deletions(-)
>> >>
>> >> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
>> >> index 16688f5..cfebd48 100644
>> >> --- a/drivers/base/dd.c
>> >> +++ b/drivers/base/dd.c
>> >> @@ -19,6 +19,7 @@
>> >>
>> >> #include <linux/device.h>
>> >> #include <linux/delay.h>
>> >> +#include <linux/dma-mapping.h>
>> >> #include <linux/module.h>
>> >> #include <linux/kthread.h>
>> >> #include <linux/wait.h>
>> >> @@ -353,6 +354,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>> >> if (ret)
>> >> goto pinctrl_bind_failed;
>> >>
>> >> + ret = dma_configure(dev);
>> >> + if (ret)
>> >> + goto dma_failed;
>> >> +
>> >> if (driver_sysfs_add(dev)) {
>> >> printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
>> >> __func__, dev_name(dev));
>> >> @@ -395,6 +400,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>> >> goto done;
>> >>
>> >> probe_failed:
>> >> + dma_deconfigure(dev);
>> >> +dma_failed:
>> >> if (dev->bus)
>> >> blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
>> >> BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
>> >> @@ -780,6 +787,9 @@ static void __device_release_driver(struct device *dev)
>> >> dev->bus->remove(dev);
>> >> else if (drv->remove)
>> >> drv->remove(dev);
>> >> +
>> >> + dma_deconfigure(dev);
>> >> +
>> >> devres_release_all(dev);
>> >> dev->driver = NULL;
>> >> dev_set_drvdata(dev, NULL);
>> >> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
>> >> index d799662..54e87f5 100644
>> >> --- a/drivers/base/dma-mapping.c
>> >> +++ b/drivers/base/dma-mapping.c
>> >> @@ -10,6 +10,7 @@
>> >> #include <linux/dma-mapping.h>
>> >> #include <linux/export.h>
>> >> #include <linux/gfp.h>
>> >> +#include <linux/of_device.h>
>> >> #include <linux/slab.h>
>> >> #include <linux/vmalloc.h>
>> >>
>> >> @@ -166,6 +167,16 @@ void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr,
>> >> }
>> >> EXPORT_SYMBOL(dmam_free_noncoherent);
>> >>
>> >> +int dma_configure(struct device *dev)
>> >> +{
>> >> + return of_dma_configure(dev, dev->of_node);
>> >> +}
>> >> +
>> >> +void dma_deconfigure(struct device *dev)
>> >> +{
>> >> + of_dma_deconfigure(dev);
>> >> +}
>> >> +
>> >> #ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
>> >>
>> >> static void dmam_coherent_decl_release(struct device *dev, void *res)
>> >> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
>> >> index 9cb7090..adbd77c 100644
>> >> --- a/drivers/of/platform.c
>> >> +++ b/drivers/of/platform.c
>> >> @@ -181,11 +181,9 @@ static struct platform_device *of_platform_device_create_pdata(
>> >>
>> >> dev->dev.bus = &platform_bus_type;
>> >> dev->dev.platform_data = platform_data;
>> >> - of_dma_configure(&dev->dev, dev->dev.of_node);
>> >> of_msi_configure(&dev->dev, dev->dev.of_node);
>> >>
>> >> if (of_device_add(dev) != 0) {
>> >> - of_dma_deconfigure(&dev->dev);
>> >> platform_device_put(dev);
>> >> goto err_clear_flag;
>> >> }
>> >> @@ -242,7 +240,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
>> >> dev_set_name(&dev->dev, "%s", bus_id);
>> >> else
>> >> of_device_make_bus_id(&dev->dev);
>> >> - of_dma_configure(&dev->dev, dev->dev.of_node);
>> >>
>> >> /* Allow the HW Peripheral ID to be overridden */
>> >> prop = of_get_property(node, "arm,primecell-periphid", NULL);
>> >> @@ -536,7 +533,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
>> >> amba_device_unregister(to_amba_device(dev));
>> >> #endif
>> >>
>> >> - of_dma_deconfigure(dev);
>> >> of_node_clear_flag(dev->of_node, OF_POPULATED);
>> >> of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
>> >> return 0;
>> >> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> >> index 93f280d..85c9553 100644
>> >> --- a/drivers/pci/probe.c
>> >> +++ b/drivers/pci/probe.c
>> >> @@ -1724,10 +1724,7 @@ static void pci_dma_configure(struct pci_dev *dev)
>> >> {
>> >> struct device *bridge = pci_get_host_bridge_device(dev);
>> >>
>> >> - if (IS_ENABLED(CONFIG_OF) &&
>> >> - bridge->parent && bridge->parent->of_node) {
>> >> - of_dma_configure(&dev->dev, bridge->parent->of_node);
>> >> - } else if (has_acpi_companion(bridge)) {
>> >> + if (has_acpi_companion(bridge)) {
>> >> struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
>> >> enum dev_dma_attr attr = acpi_get_dma_attr(adev);
>> >
>> >It seems a bit awkward leaving pci_dma_configure here, doing DMA
>> >configuration at device add, after we've allegedly moved DMA
>> >configuration to driver probe. Lorenzo, do you foresee any issues if
>> >this probe-time of_dma_configure() path were to also multiplex
>> >acpi_dma_configure() in future, such that everything would be back in
>> >the same place eventually?
>> >
>> >Conversely, is there actually any issue with leaving pci_dma_configure()
>> >unchanged, and simply moving the call from pci_device_add() into
>> >dma_configure()?
>>
>> Ya i removed only the CONFIG_OF part out of this, and was hoping that
>> the acpi configure can also be called from the dma_configure during
>> probe later. I did not have an ACPI based platform though. As you
>> said, if that looks right to the ACPI world, it can be moved out from
>> here. I can try mergin series (after fixing the vfio errors part) with
>> the ACPI IO port and see how it behaves.
>
>I do not expect any issue from this change, as long as, as Robin said,
>it is done consistently which means that I am not ok with this patch
>as it stands (ie you should defer pci_dma_configure() in its entirety,
>not just the DT bits, which obviously requires some ACPI testing too).
>
>CC me in please in the next posting since this affects the ACPI probing
>path too, we have to coordinate this series with my ACPI IORT SMMU
>enablement patches:
>
>https://lkml.org/lkml/2016/10/18/506
Ok thanks, i will have you in looped for the V4 i am posting
and we can have it tested on ACPI as well.
Regards,
Sricharan
^ permalink raw reply
* [PATCH 1/5] ARM: dts: imx: add Boundary Devices Nitrogen6_SOM2 support
From: Shawn Guo @ 2016-11-02 7:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAAMH-yugLeHjaSwMx9ZoJ9qm44VKXcgO64xdsO=HBj59pj5cUA@mail.gmail.com>
On Tue, Nov 01, 2016 at 03:54:31PM +0100, Gary Bisson wrote:
> Hi Shawn,
>
> On Tue, Nov 1, 2016 at 3:13 PM, Shawn Guo <shawnguo@kernel.org> wrote:
> > On Tue, Oct 25, 2016 at 11:19:51PM +0200, Gary Bisson wrote:
> >> SoM based on i.MX6 Quad with 1GB of DDR3.
> >>
> >> https://boundarydevices.com/product/nit6x-som-v2/
> >>
> >> Signed-off-by: Gary Bisson <gary.bisson@boundarydevices.com>
> >> ---
> >> arch/arm/boot/dts/Makefile | 1 +
> >> arch/arm/boot/dts/imx6q-nitrogen6_som2.dts | 53 ++
> >> arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi | 770 ++++++++++++++++++++++++++
> >> 3 files changed, 824 insertions(+)
> >> create mode 100644 arch/arm/boot/dts/imx6q-nitrogen6_som2.dts
> >> create mode 100644 arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
> >
> > <snip>
> >
> >> +/ {
> >> + chosen {
> >> + stdout-path = &uart2;
> >> + };
> >> +
> >> + memory {
> >> + reg = <0x10000000 0x40000000>;
> >> + };
> >> +
> >> + backlight_lcd: backlight_lcd {
> >
> > Please use hyphen instead of underscore in node name. Please check
> > through the patch series.
>
> Sorry about that, forgot (again). Just to make sure, the label can
> have underscore but not the name right? Or is it better to have hypens
> everywhere?
Hyphen cannot be used in labels. Otherwise, DTC will complain.
> So I guess I need to make a pass on current boards as well.
I'm fine with the current boards and only expect it to be right with the
boards to be added.
Shawn
^ permalink raw reply
* [PATCH v2 0/4] ASoC: DAPM: Support stereo controls shared between widgets
From: Chen-Yu Tsai @ 2016-11-02 7:35 UTC (permalink / raw)
To: linux-arm-kernel
Hi everyone,
This was part of my Allwinner A31 audio codec support series. As I split
up some patches, the series was getting somewhat large. Hence I'm sending
out the ASoC DAPM core changes separately. The remaining Allwinner
specific patches will be sent later. The complete series can be found
here [1], if people need a real use case as reference.
While DAPM is mono or single channel, its controls can be shared between
widgets, such as sharing one stereo mixer control between the left and
right channel widgets. An example such as the following routes
[Line In Left]----------<Line In Playback Switch>-------[Left Mixer]
^
^ ^ | ^
(inputs) (paths) <shared stereo mixer control> (outputs)
v v | v
v
[Line In Right]---------<Line In Playback Switch>-------[Right Mixer]
where we have separate widgets and paths for the left and right channels
from "Line In" to "Mixer", but a shared stereo mixer control for the
2 paths. By having a stereo mixer control, we expose to userspace a sane
mixer interface. Otherwise we would have a bunch of "X Left Playback Switch"
and "X Right Playback Switch" controls.
This series introduces support for such shared mixer controls, allowing
more than 1 path to be attached to a single stereo control, and allowing
control of left/right channels independently. The DAPM control types
DAPM_DOUBLE and DAPM_DOUBLE_R are added.
Changes since v1:
- Expaned commit message for "ASoC: dapm: Implement stereo mixer
control support"
- Expanded comments in dapm_set_mixer_path_status and
soc_dapm_mixer_update_power
- Check assumption of field width < (bits in unsigned int / 2) in
snd_soc_dapm_put_volsw
- Print warning when adding stereo "autodisable" controls which is not
supported
- Use NULL for struct snd_soc_dapm_update initializer, as the first
field is a pointer, to avoid compiler warnings.
Regards
ChenYu
[1] https://github.com/wens/linux/commits/a31-audio-v2
Chen-Yu Tsai (4):
ASoC: dapm: Support second register for DAPM control updates
ASoC: dapm: Implement stereo mixer control support
ASoC: dapm: Introduce DAPM_DOUBLE dual channel control type
ASoC: dapm: Introduce DAPM_DOUBLE_R dual channel dual register control
type
include/sound/soc-dapm.h | 14 ++++
sound/soc/codecs/adau17x1.c | 2 +-
sound/soc/codecs/tlv320aic3x.c | 2 +-
sound/soc/codecs/wm9712.c | 2 +-
sound/soc/codecs/wm9713.c | 2 +-
sound/soc/soc-dapm.c | 154 ++++++++++++++++++++++++++++++++---------
6 files changed, 141 insertions(+), 35 deletions(-)
--
2.10.2
^ permalink raw reply
* [PATCH v2 1/4] ASoC: dapm: Support second register for DAPM control updates
From: Chen-Yu Tsai @ 2016-11-02 7:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161102073601.8659-1-wens@csie.org>
To support double channel shared controls split across 2 registers, one
for each channel, we must be able to update both registers together.
Add a second set of register fields to struct snd_soc_dapm_update, and
update the DAPM control writeback (put) callbacks to support this.
For codecs that use custom events which call into DAPM to do updates,
also clear struct snd_soc_dapm_update before using it, so the second
set of fields remains clean.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
include/sound/soc-dapm.h | 4 ++++
sound/soc/codecs/adau17x1.c | 2 +-
sound/soc/codecs/tlv320aic3x.c | 2 +-
sound/soc/codecs/wm9712.c | 2 +-
sound/soc/codecs/wm9713.c | 2 +-
sound/soc/soc-dapm.c | 13 +++++++++++--
6 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index f60d755f7ac6..d5f4677776ce 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -615,6 +615,10 @@ struct snd_soc_dapm_update {
int reg;
int mask;
int val;
+ int reg2;
+ int mask2;
+ int val2;
+ bool has_second_set;
};
struct snd_soc_dapm_wcache {
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 439aa3ff1f99..b36511d965c8 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -160,7 +160,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- struct snd_soc_dapm_update update;
+ struct snd_soc_dapm_update update = { 0 };
unsigned int stream = e->shift_l;
unsigned int val, change;
int reg;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 5a8d96ec058c..8877b74b0510 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -157,7 +157,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
unsigned short val;
- struct snd_soc_dapm_update update;
+ struct snd_soc_dapm_update update = { 0 };
int connect, change;
val = (ucontrol->value.integer.value[0] & mask);
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 557709eac698..85f7c5bb8b82 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -187,7 +187,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int mixer, mask, shift, old;
- struct snd_soc_dapm_update update;
+ struct snd_soc_dapm_update update = { 0 };
bool change;
mixer = mc->shift >> 8;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index e4301ddb1b84..7e4822185feb 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -231,7 +231,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int mixer, mask, shift, old;
- struct snd_soc_dapm_update update;
+ struct snd_soc_dapm_update update = { 0 };
bool change;
mixer = mc->shift >> 8;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 3bbe32ee4630..32e7af9b93d5 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1626,6 +1626,15 @@ static void dapm_widget_update(struct snd_soc_card *card)
dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
w->name, ret);
+ if (update->has_second_set) {
+ ret = soc_dapm_update_bits(w->dapm, update->reg2,
+ update->mask2, update->val2);
+ if (ret < 0)
+ dev_err(w->dapm->dev,
+ "ASoC: %s DAPM update failed: %d\n",
+ w->name, ret);
+ }
+
for (wi = 0; wi < wlist->num_widgets; wi++) {
w = wlist->widgets[wi];
@@ -3084,7 +3093,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int invert = mc->invert;
unsigned int val;
int connect, change, reg_change = 0;
- struct snd_soc_dapm_update update;
+ struct snd_soc_dapm_update update = { NULL };
int ret = 0;
if (snd_soc_volsw_is_stereo(mc))
@@ -3192,7 +3201,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
unsigned int *item = ucontrol->value.enumerated.item;
unsigned int val, change, reg_change = 0;
unsigned int mask;
- struct snd_soc_dapm_update update;
+ struct snd_soc_dapm_update update = { NULL };
int ret = 0;
if (item[0] >= e->items)
--
2.10.2
^ permalink raw reply related
* [PATCH v2 2/4] ASoC: dapm: Implement stereo mixer control support
From: Chen-Yu Tsai @ 2016-11-02 7:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161102073601.8659-1-wens@csie.org>
While DAPM is mono or single channel, its controls can be shared between
widgets, such as sharing one stereo mixer control between the left and
right channel widgets. An example such as the following routes
[Line In Left]----------<Line In Playback Switch>-------[Left Mixer]
^
^ ^ | ^
(inputs) (paths) <shared stereo mixer control> (outputs)
v v | v
v
[Line In Right]---------<Line In Playback Switch>-------[Right Mixer]
where we have separate widgets and paths for the left and right channels
from "Line In" to "Mixer", but a shared stereo mixer control for the
2 paths.
This patch introduces support for such shared mixer controls, allowing
more than 1 path to be attached to a single stereo control, and being
able to control left/right channels independently.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
sound/soc/soc-dapm.c | 141 ++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 112 insertions(+), 29 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 32e7af9b93d5..27dd02e57b31 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -330,6 +330,11 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
case snd_soc_dapm_mixer_named_ctl:
mc = (struct soc_mixer_control *)kcontrol->private_value;
+ if (mc->autodisable && snd_soc_volsw_is_stereo(mc))
+ dev_warn(widget->dapm->dev,
+ "ASoC: Unsupported stereo autodisable control '%s'\n",
+ ctrl_name);
+
if (mc->autodisable) {
struct snd_soc_dapm_widget template;
@@ -723,7 +728,8 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
}
/* set up initial codec paths */
-static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
+static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
+ int nth_path)
{
struct soc_mixer_control *mc = (struct soc_mixer_control *)
p->sink->kcontrol_news[i].private_value;
@@ -736,7 +742,25 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
if (reg != SND_SOC_NOPM) {
soc_dapm_read(p->sink->dapm, reg, &val);
- val = (val >> shift) & mask;
+ /*
+ * The nth_path argument allows this function to know
+ * which path of a kcontrol it is setting the initial
+ * status for. Ideally this would support any number
+ * of paths and channels. But since kcontrols only come
+ * in mono and stereo variants, we are limited to 2
+ * channels.
+ *
+ * The following code assumes for stereo controls the
+ * first path is the left channel, and all remaining
+ * paths are the right channel.
+ */
+ if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
+ if (reg != mc->rreg)
+ soc_dapm_read(p->sink->dapm, mc->rreg, &val);
+ val = (val >> mc->rshift) & mask;
+ } else {
+ val = (val >> shift) & mask;
+ }
if (invert)
val = max - val;
p->connect = !!val;
@@ -749,13 +773,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_path *path, const char *control_name)
{
- int i;
+ int i, nth_path = 0;
/* search for mixer kcontrol */
for (i = 0; i < path->sink->num_kcontrols; i++) {
if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
path->name = path->sink->kcontrol_news[i].name;
- dapm_set_mixer_path_status(path, i);
+ dapm_set_mixer_path_status(path, i, nth_path++);
return 0;
}
}
@@ -2186,7 +2210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */
static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
- struct snd_kcontrol *kcontrol, int connect)
+ struct snd_kcontrol *kcontrol,
+ int connect, int rconnect)
{
struct snd_soc_dapm_path *path;
int found = 0;
@@ -2195,8 +2220,33 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
/* find dapm widget path assoc with kcontrol */
dapm_kcontrol_for_each_path(path, kcontrol) {
+ /*
+ * Ideally this function should support any number of
+ * paths and channels. But since kcontrols only come
+ * in mono and stereo variants, we are limited to 2
+ * channels.
+ *
+ * The following code assumes for stereo controls the
+ * first path (when 'found == 0') is the left channel,
+ * and all remaining paths (when 'found == 1') are the
+ * right channel.
+ *
+ * A stereo control is signified by a valid 'rconnect'
+ * value, either 0 for unconnected, or >= 0 for connected.
+ * This is chosen instead of using snd_soc_volsw_is_stereo,
+ * so that the behavior of snd_soc_dapm_mixer_update_power
+ * doesn't change even when the kcontrol passed in is
+ * stereo.
+ *
+ * It passes 'connect' as the path connect status for
+ * the left channel, and 'rconnect' for the right
+ * channel.
+ */
+ if (found && rconnect >= 0)
+ soc_dapm_connect_path(path, rconnect, "mixer update");
+ else
+ soc_dapm_connect_path(path, connect, "mixer update");
found = 1;
- soc_dapm_connect_path(path, connect, "mixer update");
}
if (found)
@@ -2214,7 +2264,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
card->update = update;
- ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
+ ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
card->update = NULL;
mutex_unlock(&card->dapm_mutex);
if (ret > 0)
@@ -3039,22 +3089,28 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
int reg = mc->reg;
unsigned int shift = mc->shift;
int max = mc->max;
+ unsigned int width = fls(max);
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- unsigned int val;
+ unsigned int reg_val, val, rval = 0;
int ret = 0;
- if (snd_soc_volsw_is_stereo(mc))
- dev_warn(dapm->dev,
- "ASoC: Control '%s' is stereo, which is not supported\n",
- kcontrol->id.name);
-
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
- ret = soc_dapm_read(dapm, reg, &val);
- val = (val >> shift) & mask;
+ ret = soc_dapm_read(dapm, reg, ®_val);
+ val = (reg_val >> shift) & mask;
+
+ if (ret == 0 && reg != mc->rreg)
+ ret = soc_dapm_read(dapm, mc->rreg, ®_val);
+
+ if (snd_soc_volsw_is_stereo(mc))
+ rval = (reg_val >> mc->rshift) & mask;
} else {
- val = dapm_kcontrol_get_value(kcontrol);
+ reg_val = dapm_kcontrol_get_value(kcontrol);
+ val = reg_val & mask;
+
+ if (snd_soc_volsw_is_stereo(mc))
+ rval = (reg_val >> width) & mask;
}
mutex_unlock(&card->dapm_mutex);
@@ -3066,6 +3122,13 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
else
ucontrol->value.integer.value[0] = val;
+ if (snd_soc_volsw_is_stereo(mc)) {
+ if (invert)
+ ucontrol->value.integer.value[1] = max - rval;
+ else
+ ucontrol->value.integer.value[1] = rval;
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
@@ -3089,46 +3152,66 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
int reg = mc->reg;
unsigned int shift = mc->shift;
int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int width = fls(max);
+ unsigned int mask = (1 << width) - 1;
unsigned int invert = mc->invert;
- unsigned int val;
- int connect, change, reg_change = 0;
+ unsigned int val, rval = 0;
+ int connect, rconnect = -1, change, reg_change = 0;
struct snd_soc_dapm_update update = { NULL };
int ret = 0;
- if (snd_soc_volsw_is_stereo(mc))
- dev_warn(dapm->dev,
- "ASoC: Control '%s' is stereo, which is not supported\n",
- kcontrol->id.name);
-
val = (ucontrol->value.integer.value[0] & mask);
connect = !!val;
if (invert)
val = max - val;
+ if (snd_soc_volsw_is_stereo(mc)) {
+ rval = (ucontrol->value.integer.value[1] & mask);
+ rconnect = !!rval;
+ if (invert)
+ rval = max - rval;
+ }
+
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- change = dapm_kcontrol_set_value(kcontrol, val);
+ /* This assumes field width < (bits in unsigned int / 2) */
+ if (width > sizeof(unsigned int) * 8 / 2)
+ dev_warn(dapm->dev,
+ "ASoC: control %s field width limit exceeded\n",
+ kcontrol->id.name);
+ change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
if (reg != SND_SOC_NOPM) {
- mask = mask << shift;
val = val << shift;
+ rval = rval << mc->rshift;
+
+ reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
- reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
+ if (snd_soc_volsw_is_stereo(mc))
+ reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
+ mask << mc->rshift,
+ rval);
}
if (change || reg_change) {
if (reg_change) {
+ if (snd_soc_volsw_is_stereo(mc)) {
+ update.has_second_set = true;
+ update.reg2 = mc->rreg;
+ update.mask2 = mask << mc->rshift;
+ update.val2 = rval;
+ }
update.kcontrol = kcontrol;
update.reg = reg;
- update.mask = mask;
+ update.mask = mask << shift;
update.val = val;
card->update = &update;
}
change |= reg_change;
- ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
+ ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
+ rconnect);
card->update = NULL;
}
--
2.10.2
^ permalink raw reply related
* [PATCH v2 3/4] ASoC: dapm: Introduce DAPM_DOUBLE dual channel control type
From: Chen-Yu Tsai @ 2016-11-02 7:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161102073601.8659-1-wens@csie.org>
A DAPM_DOUBLE control type can be used for dual channel mixer input
selectors / mute controls in one register, possibly toggling both
channels together.
The control is meant to be shared by 2 widgets, 1 for each channel,
such that the mixer control exposed to userspace remains a combined
stereo control.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
include/sound/soc-dapm.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index d5f4677776ce..f74ec19687f8 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -272,6 +272,11 @@ struct device;
/* dapm kcontrol types */
+#define SOC_DAPM_DOUBLE(xname, reg, lshift, rshift, max, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+ .private_value = SOC_DOUBLE_VALUE(reg, lshift, rshift, max, invert, 0) }
#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \
--
2.10.2
^ permalink raw reply related
* [PATCH v2 4/4] ASoC: dapm: Introduce DAPM_DOUBLE_R dual channel dual register control type
From: Chen-Yu Tsai @ 2016-11-02 7:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161102073601.8659-1-wens@csie.org>
A DAPM_DOUBLE_R control type can be used for dual channel mixer input
selectors / mute controls across 2 registers, possibly toggling both
channels together.
The control is meant to be shared by 2 widgets, 1 for each channel,
such that the mixer control exposed to userspace remains a combined
stereo control.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
include/sound/soc-dapm.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index f74ec19687f8..a466f4bdc835 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -277,6 +277,11 @@ struct device;
.info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_DOUBLE_VALUE(reg, lshift, rshift, max, invert, 0) }
+#define SOC_DAPM_DOUBLE_R(xname, lreg, rreg, shift, max, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+ .private_value = SOC_DOUBLE_R_VALUE(lreg, rreg, shift, max, invert) }
#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \
--
2.10.2
^ permalink raw reply related
* [PATCH v2 0/5] ARM: dts: imx: update Boundary Devices boards support
From: Shawn Guo @ 2016-11-02 7:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161101171006.24594-1-gary.bisson@boundarydevices.com>
On Tue, Nov 01, 2016 at 06:10:01PM +0100, Gary Bisson wrote:
> Gary Bisson (5):
> ARM: dts: imx: add Boundary Devices Nitrogen6_SOM2 support
> ARM: dts: imx6qdl-sabrelite: use hyphens for nodes name
> ARM: dts: imx6qdl-nitrogen6x: use hyphens for nodes name
> ARM: dts: imx6qdl-nit6xlite: use hyphens for nodes name
> ARM: dts: imx6qdl-nitrogen6_max: use hyphens for nodes name
Applied all, thanks.
^ permalink raw reply
* [PATCH 0/2] support USB2 PHY OTG port for rk3399
From: William Wu @ 2016-11-02 7:42 UTC (permalink / raw)
To: linux-arm-kernel
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
* [PATCH 1/2] phy: rockchip-inno-usb2: support otg-port for rk3399
From: William Wu @ 2016-11-02 7:42 UTC (permalink / raw)
To: linux-arm-kernel
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 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: linux-arm-kernel
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 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: linux-arm-kernel
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
^ permalink raw reply
* [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: linux-arm-kernel
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 at 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
^ 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: linux-arm-kernel
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
^ permalink raw reply related
* [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: linux-arm-kernel
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
^ permalink raw reply related
* [PATCHv2 3/4] mfd: altr-a10sr: Add Arria10 SR Monitor
From: Lee Jones @ 2016-11-02 8:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <39faa26d-ca05-d68d-a50a-03d09d445b77@opensource.altera.com>
On Mon, 31 Oct 2016, Thor Thayer wrote:
> On 10/31/2016 03:02 AM, Lee Jones wrote:
> > On Thu, 27 Oct 2016, tthayer at opensource.altera.com wrote:
> >
> > > From: Thor Thayer <tthayer@opensource.altera.com>
> > >
> > > Add the Altera Arria10 DevKit System Resource Monitor functionality
> > > to the MFD device.
> > >
> > > Signed-off-by: Thor Thayer <tthayer@opensource.altera.com>
> > > ---
> > > 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@linaro.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
^ permalink raw reply
* [PATCH] clk: stm32f4: don't assume 48MHz clock is derived from primary PLL
From: Gabriel Fernandez @ 2016-11-02 8:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161102004401.GR16026@codeaurora.org>
On 11/02/2016 01:44 AM, Stephen Boyd wrote:
> On 09/12, Andrea Merello wrote:
>> On Fri, Sep 9, 2016 at 11:57 AM, Alexandre Torgue
>> <alexandre.torgue@st.com> wrote:
>>> Hi Andrea,
>>>
>>> On 09/08/2016 09:01 AM, Andrea Merello wrote:
>>>> This driver just look at the PLLs configurations set by the
>>>> bootloader, but it assumes the 48MHz clock is derived from the primary
>>>> PLL; however using PLLSAI is another option for generating the 48MHz
>>>> clock.
>>>>
>>>> This patch make the driver to check for this, and eventually adjust the
>>>> clock tree accordingly
>>>
>>> Another patch-set is ongoing concerning RTC clock for stm32f4. It is
>>> developed by Gabriel Fernandez (I add him directly in this reply).
>>> Can you check with him how he plans to manage this RTC clock in order to
>>> have something similar / coherent for SAI clocks, 48MHz ....
>>>
>>> Concerning this patch,
>>> When I look at the clock tree I see that 48 MHz is only provided by pll
>>> named "PLL". So If you use PLL SAI to provide a clock at 48 MHz, you
>>> actually use SAI_A or SAI_B clock. I'm right ?
>> No, SAI_A and SAI_B are two other clocks output, that comes from
>> PLLSAI through other divisors and muxes; here I simply look at if the
>> bootloader selected the "PLL48CLK" output of the SAI PLL instead of
>> the "PLL48CLK" of the primary PLL.
>>
>>> I think we need to have something more configurable. Each special clock (SAI
>>> / RTC /LCd ...) hav0000000000000000000000000000000000000001e to be configurable and each "parents" (PLL / PLLI2S /
>>> PLLSAI) should be described at least in the driver.
>> Yes, there are probably other possible clock configurations that the
>> driver does not recognize yet; I just added this one because I found
>> it useful in real-world scenario (USB/SDcard working and core running
>> at the max speed at the same time).
>>
>>> Gabriel,
>>>
>>> Can you send a draft of your patch-set for RTC clock to Andrea, in order to
>>> discuss about this topic.
>>>
>>> Thanks
> I know this is a couple months old, but the RTC patches have been
> applied. Please resend this patch rebased onto clk-next and
> restart this discussion if this is still important.
>
Hi Stephen & Andrea,
As discuss with Andrea, i will send a second patch-set to introduce
PLL-I2S & PLL-SAI (it will include the management of the 48 Mhz Clock)
I will probably send it today or tomorrow.
Thanks
Best Regard.
Gabriel
^ permalink raw reply
* [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: linux-arm-kernel
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 at 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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox