* [PATCH/RFT v2 01/17] ARM: davinci: da8xx: add usb phy clocks
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
Up to this point, the USB phy clock configuration was handled manually in
the board files and in the usb drivers. This adds proper clocks so that
the usb drivers can use clk_get and clk_enable and not have to worry about
the details. Also, the related code is removed from the board files and
replaced with the new clock registration functions.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 22 ++-
arch/arm/mach-davinci/board-omapl138-hawk.c | 16 +-
arch/arm/mach-davinci/include/mach/da8xx.h | 3 +
arch/arm/mach-davinci/usb-da8xx.c | 219 +++++++++++++++++++++++++++-
4 files changed, 239 insertions(+), 21 deletions(-)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 3d8cf8c..605d444 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -115,18 +115,6 @@ static __init void da830_evm_usb_init(void)
*/
cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
- /* USB2.0 PHY reference clock is 24 MHz */
- cfgchip2 &= ~CFGCHIP2_REFFREQ;
- cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
-
- /*
- * Select internal reference clock for USB 2.0 PHY
- * and use it as a clock source for USB 1.1 PHY
- * (this is the default setting anyway).
- */
- cfgchip2 &= ~CFGCHIP2_USB1PHYCLKMUX;
- cfgchip2 |= CFGCHIP2_USB2PHYCLKMUX;
-
/*
* We have to override VBUS/ID signals when MUSB is configured into the
* host-only mode -- ID pin will float if no cable is connected, so the
@@ -143,6 +131,16 @@ static __init void da830_evm_usb_init(void)
__raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
/* USB_REFCLKIN is not used. */
+ ret = da8xx_register_usb20_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 2.0 PHY CLK registration failed: %d\n",
+ __func__, ret);
+
+ ret = da8xx_register_usb11_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
+ __func__, ret);
+
ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
if (ret)
pr_warn("%s: USB 2.0 PinMux setup failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index ee62486..d4930b6 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -243,7 +243,6 @@ static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id)
static __init void omapl138_hawk_usb_init(void)
{
int ret;
- u32 cfgchip2;
ret = davinci_cfg_reg_list(da850_hawk_usb11_pins);
if (ret) {
@@ -251,12 +250,15 @@ static __init void omapl138_hawk_usb_init(void)
return;
}
- /* Setup the Ref. clock frequency for the HAWK at 24 MHz. */
-
- cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
- cfgchip2 &= ~CFGCHIP2_REFFREQ;
- cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
- __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ /* USB_REFCLKIN is not used. */
+ ret = da8xx_register_usb20_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 2.0 PHY CLK registration failed: %d\n",
+ __func__, ret);
+ ret = da8xx_register_usb11_phy_clk(false);
+ if (ret)
+ pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
+ __func__, ret);
ret = gpio_request_one(DA850_USB1_VBUS_PIN,
GPIOF_DIR_OUT, "USB1 VBUS");
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index f9f9713..c367530 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -88,6 +88,9 @@
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
int da8xx_register_spi_bus(int instance, unsigned num_chipselect);
int da8xx_register_watchdog(void);
+int da8xx_register_usb_refclkin(int rate);
+int da8xx_register_usb20_phy_clk(bool use_usb_refclkin);
+int da8xx_register_usb11_phy_clk(bool use_usb_refclkin);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
int da8xx_register_emac(void);
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index f141f51..c524d9e 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -1,20 +1,235 @@
/*
* DA8xx USB
*/
-#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <linux/platform_data/usb-davinci.h>
#include <linux/platform_device.h>
+#include <linux/mfd/da8xx-cfgchip.h>
#include <linux/usb/musb.h>
+#include <mach/clock.h>
#include <mach/common.h>
#include <mach/cputype.h>
#include <mach/da8xx.h>
-#include <mach/irqs.h>
+
+#include "clock.h"
#define DA8XX_USB0_BASE 0x01e00000
#define DA8XX_USB1_BASE 0x01e25000
+static struct clk usb_refclkin = {
+ .name = "usb_refclkin",
+ .set_rate = davinci_simple_set_rate,
+};
+
+static struct clk_lookup usb_refclkin_lookup =
+ CLK(NULL, "usb_refclkin", &usb_refclkin);
+
+/**
+ * da8xx_register_usb_refclkin - register USB_REFCLKIN clock
+ *
+ * @rate: The clock rate in Hz
+ *
+ * This clock is only needed if the board provides an external USB_REFCLKIN
+ * signal, in which case it will be used as the parent of usb20_phy_clk and/or
+ * usb11_phy_clk.
+ */
+int __init da8xx_register_usb_refclkin(int rate)
+{
+ int ret;
+
+ usb_refclkin.rate = rate;
+ ret = clk_register(&usb_refclkin);
+ if (ret)
+ return ret;
+
+ clkdev_add(&usb_refclkin_lookup);
+
+ return 0;
+}
+
+static void usb20_phy_clk_enable(struct clk *clk)
+{
+ u32 val;
+ u32 timeout = 500000; /* 500 msec */
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /*
+ * Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1
+ * host may use the PLL clock without USB 2.0 OTG being used.
+ */
+ val &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN);
+ val |= CFGCHIP2_PHY_PLLON;
+
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ while (--timeout) {
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ if (val & CFGCHIP2_PHYCLKGD)
+ return;
+ udelay(1);
+ }
+
+ pr_err("Timeout waiting for USB 2.0 PHY clock good.\n");
+}
+
+static void usb20_phy_clk_disable(struct clk *clk)
+{
+ u32 val;
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ val |= CFGCHIP2_PHYPWRDN;
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+}
+
+static int usb20_phy_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 val;
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /* Set the mux depending on the parent clock. */
+ if (parent == &usb_refclkin) {
+ val &= ~CFGCHIP2_USB2PHYCLKMUX;
+ } else if (strcmp(parent->name, "pll0_aux_clk") == 0) {
+ val |= CFGCHIP2_USB2PHYCLKMUX;
+ } else {
+ pr_err("Bad parent on USB 2.0 PHY clock.\n");
+ return -EINVAL;
+ }
+
+ /* reference frequency also comes from parent clock */
+ val &= ~CFGCHIP2_REFFREQ_MASK;
+ switch (clk_get_rate(parent)) {
+ case 12000000:
+ val |= CFGCHIP2_REFFREQ_12MHZ;
+ break;
+ case 13000000:
+ val |= CFGCHIP2_REFFREQ_13MHZ;
+ break;
+ case 19200000:
+ val |= CFGCHIP2_REFFREQ_19_2MHZ;
+ break;
+ case 20000000:
+ val |= CFGCHIP2_REFFREQ_20MHZ;
+ break;
+ case 24000000:
+ val |= CFGCHIP2_REFFREQ_24MHZ;
+ break;
+ case 26000000:
+ val |= CFGCHIP2_REFFREQ_26MHZ;
+ break;
+ case 38400000:
+ val |= CFGCHIP2_REFFREQ_38_4MHZ;
+ break;
+ case 40000000:
+ val |= CFGCHIP2_REFFREQ_40MHZ;
+ break;
+ case 48000000:
+ val |= CFGCHIP2_REFFREQ_48MHZ;
+ break;
+ default:
+ pr_err("Bad parent clock rate on USB 2.0 PHY clock.\n");
+ return -EINVAL;
+ }
+
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ return 0;
+}
+
+static struct clk usb20_phy_clk = {
+ .name = "usb20_phy",
+ .clk_enable = usb20_phy_clk_enable,
+ .clk_disable = usb20_phy_clk_disable,
+ .set_parent = usb20_phy_clk_set_parent,
+};
+
+static struct clk_lookup usb20_phy_clk_lookup =
+ CLK(NULL, "usb20_phy", &usb20_phy_clk);
+
+/**
+ * da8xx_register_usb20_phy_clk - register USB0PHYCLKMUX clock
+ *
+ * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true
+ * or "pll0_aux" if false.
+ */
+int __init da8xx_register_usb20_phy_clk(bool use_usb_refclkin)
+{
+ struct clk *parent;
+ int ret = 0;
+
+ parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "pll0_aux");
+ if (IS_ERR(parent))
+ return PTR_ERR(parent);
+
+ usb20_phy_clk.parent = parent;
+ ret = clk_register(&usb20_phy_clk);
+ if (!ret)
+ clkdev_add(&usb20_phy_clk_lookup);
+
+ clk_put(parent);
+
+ return ret;
+}
+
+static int usb11_phy_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 val;
+
+ val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /* Set the USB 1.1 PHY clock mux based on the parent clock. */
+ if (parent == &usb20_phy_clk) {
+ val &= ~CFGCHIP2_USB1PHYCLKMUX;
+ } else if (parent == &usb_refclkin) {
+ val |= CFGCHIP2_USB1PHYCLKMUX;
+ } else {
+ pr_err("Bad parent on USB 1.1 PHY clock.\n");
+ return -EINVAL;
+ }
+
+ writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ return 0;
+}
+
+static struct clk usb11_phy_clk = {
+ .name = "usb11_phy",
+ .set_parent = usb11_phy_clk_set_parent,
+};
+
+static struct clk_lookup usb11_phy_clk_lookup =
+ CLK(NULL, "usb11_phy", &usb11_phy_clk);
+
+/**
+ * da8xx_register_usb11_phy_clk - register USB1PHYCLKMUX clock
+ *
+ * @use_usb_refclkin: Selects the parent clock - either "usb_refclkin" if true
+ * or "usb20_phy" if false.
+ */
+int __init da8xx_register_usb11_phy_clk(bool use_usb_refclkin)
+{
+ struct clk *parent;
+ int ret = 0;
+
+ parent = clk_get(NULL, use_usb_refclkin ? "usb_refclkin" : "usb20_phy");
+ if (IS_ERR(parent))
+ return PTR_ERR(parent);
+
+ usb11_phy_clk.parent = parent;
+ ret = clk_register(&usb11_phy_clk);
+ if (!ret)
+ clkdev_add(&usb11_phy_clk_lookup);
+
+ clk_put(parent);
+
+ return ret;
+}
+
#if IS_ENABLED(CONFIG_USB_MUSB_HDRC)
static struct musb_hdrc_config musb_config = {
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 02/17] ARM: davinci: da8xx: Add CFGCHIP syscon platform declaration.
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
The CFGCHIP registers are used by a number of devices, so using a syscon
device to share them. The first consumer of this will by the phy-da8xx-usb
driver.
Signed-off-by: David Lechner <david@lechnology.com>
[Axel: minor fix: change id to -1]
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 4 ++++
arch/arm/mach-davinci/board-da850-evm.c | 4 ++++
arch/arm/mach-davinci/board-mityomapl138.c | 4 ++++
arch/arm/mach-davinci/board-omapl138-hawk.c | 4 ++++
arch/arm/mach-davinci/devices-da8xx.c | 28 ++++++++++++++++++++++++++++
arch/arm/mach-davinci/include/mach/da8xx.h | 2 ++
6 files changed, 46 insertions(+)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 605d444..3051cb6 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -586,6 +586,10 @@ static __init void da830_evm_init(void)
struct davinci_soc_info *soc_info = &davinci_soc_info;
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
ret = da830_register_gpio();
if (ret)
pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 8e4539f..ec5cb10 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1345,6 +1345,10 @@ static __init void da850_evm_init(void)
{
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
ret = da850_register_gpio();
if (ret)
pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
index bc4e63f..1a6d430 100644
--- a/arch/arm/mach-davinci/board-mityomapl138.c
+++ b/arch/arm/mach-davinci/board-mityomapl138.c
@@ -514,6 +514,10 @@ static void __init mityomapl138_init(void)
{
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
/* for now, no special EDMA channels are reserved */
ret = da850_register_edma(NULL);
if (ret)
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index d4930b6..8691a25 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -294,6 +294,10 @@ static __init void omapl138_hawk_init(void)
{
int ret;
+ ret = da8xx_register_cfgchip();
+ if (ret)
+ pr_warn("%s: CFGCHIP registration failed: %d\n", __func__, ret);
+
ret = da850_register_gpio();
if (ret)
pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index add3771..31a99db 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -11,6 +11,7 @@
* (at your option) any later version.
*/
#include <linux/init.h>
+#include <linux/platform_data/syscon.h>
#include <linux/platform_device.h>
#include <linux/dma-contiguous.h>
#include <linux/serial_8250.h>
@@ -1089,3 +1090,30 @@ int __init da850_register_sata(unsigned long refclkpn)
return platform_device_register(&da850_sata_device);
}
#endif
+
+static struct syscon_platform_data da8xx_cfgchip_platform_data = {
+ .label = "cfgchip",
+};
+
+static struct resource da8xx_cfgchip_resources[] = {
+ {
+ .start = DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP0_REG,
+ .end = DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP4_REG + 3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device da8xx_cfgchip_device = {
+ .name = "syscon",
+ .id = -1,
+ .dev = {
+ .platform_data = &da8xx_cfgchip_platform_data,
+ },
+ .num_resources = ARRAY_SIZE(da8xx_cfgchip_resources),
+ .resource = da8xx_cfgchip_resources,
+};
+
+int __init da8xx_register_cfgchip(void)
+{
+ return platform_device_register(&da8xx_cfgchip_device);
+}
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index c367530..c32444b 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -61,6 +61,7 @@
#define DA8XX_CFGCHIP1_REG 0x180
#define DA8XX_CFGCHIP2_REG 0x184
#define DA8XX_CFGCHIP3_REG 0x188
+#define DA8XX_CFGCHIP4_REG 0x18c
#define DA8XX_SYSCFG1_BASE (IO_PHYS + 0x22C000)
#define DA8XX_SYSCFG1_VIRT(x) (da8xx_syscfg1_base + (x))
@@ -116,6 +117,7 @@
int da8xx_register_rproc(void);
int da850_register_gpio(void);
int da830_register_gpio(void);
+int da8xx_register_cfgchip(void);
extern struct platform_device da8xx_serial_device[];
extern struct emac_platform_data da8xx_emac_pdata;
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 03/17] ARM: davinci: da8xx: Add USB PHY platform declaration
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
There is now a proper phy driver for the DA8xx SoC USB PHY. This adds the
platform device declarations needed to use it.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 28 +++++-----------------------
arch/arm/mach-davinci/board-omapl138-hawk.c | 5 +++++
arch/arm/mach-davinci/include/mach/da8xx.h | 1 +
arch/arm/mach-davinci/usb-da8xx.c | 11 +++++++++++
4 files changed, 22 insertions(+), 23 deletions(-)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 3051cb6..c62766e 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -26,7 +26,6 @@
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
#include <linux/platform_data/spi-davinci.h>
-#include <linux/platform_data/usb-davinci.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -106,30 +105,8 @@ static irqreturn_t da830_evm_usb_ocic_irq(int irq, void *dev_id)
static __init void da830_evm_usb_init(void)
{
- u32 cfgchip2;
int ret;
- /*
- * Set up USB clock/mode in the CFGCHIP2 register.
- * FYI: CFGCHIP2 is 0x0000ef00 initially.
- */
- cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
-
- /*
- * We have to override VBUS/ID signals when MUSB is configured into the
- * host-only mode -- ID pin will float if no cable is connected, so the
- * controller won't be able to drive VBUS thinking that it's a B-device.
- * Otherwise, we want to use the OTG mode and enable VBUS comparators.
- */
- cfgchip2 &= ~CFGCHIP2_OTGMODE;
-#ifdef CONFIG_USB_MUSB_HOST
- cfgchip2 |= CFGCHIP2_FORCE_HOST;
-#else
- cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN;
-#endif
-
- __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
-
/* USB_REFCLKIN is not used. */
ret = da8xx_register_usb20_phy_clk(false);
if (ret)
@@ -141,6 +118,11 @@ static __init void da830_evm_usb_init(void)
pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
__func__, ret);
+ ret = da8xx_register_usb_phy();
+ if (ret)
+ pr_warn("%s: USB PHY registration failed: %d\n",
+ __func__, ret);
+
ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
if (ret)
pr_warn("%s: USB 2.0 PinMux setup failed: %d\n", __func__, ret);
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 8691a25..c5cb8d9 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -260,6 +260,11 @@ static __init void omapl138_hawk_usb_init(void)
pr_warn("%s: USB 1.1 PHY CLK registration failed: %d\n",
__func__, ret);
+ ret = da8xx_register_usb_phy();
+ if (ret)
+ pr_warn("%s: USB PHY registration failed: %d\n",
+ __func__, ret);
+
ret = gpio_request_one(DA850_USB1_VBUS_PIN,
GPIOF_DIR_OUT, "USB1 VBUS");
if (ret < 0) {
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index c32444b..38d932e 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -92,6 +92,7 @@
int da8xx_register_usb_refclkin(int rate);
int da8xx_register_usb20_phy_clk(bool use_usb_refclkin);
int da8xx_register_usb11_phy_clk(bool use_usb_refclkin);
+int da8xx_register_usb_phy(void);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
int da8xx_register_emac(void);
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index c524d9e..9e41a7f 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -7,6 +7,7 @@
#include <linux/platform_data/usb-davinci.h>
#include <linux/platform_device.h>
#include <linux/mfd/da8xx-cfgchip.h>
+#include <linux/phy/phy.h>
#include <linux/usb/musb.h>
#include <mach/clock.h>
@@ -230,6 +231,16 @@ int __init da8xx_register_usb11_phy_clk(bool use_usb_refclkin)
return ret;
}
+static struct platform_device da8xx_usb_phy = {
+ .name = "da8xx-usb-phy",
+ .id = 0,
+};
+
+int __init da8xx_register_usb_phy(void)
+{
+ return platform_device_register(&da8xx_usb_phy);
+}
+
#if IS_ENABLED(CONFIG_USB_MUSB_HDRC)
static struct musb_hdrc_config musb_config = {
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 04/17] ARM: DTS: da850: Add cfgchip syscon node
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
Add a syscon node for the SoC CFGCHIPn registers. This is needed for
the new usb phy driver.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/boot/dts/da850.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index f79e1b9..6bbf20d 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -188,6 +188,10 @@
};
};
+ cfgchip: cfgchip at 1417c {
+ compatible = "ti,da830-cfgchip", "syscon";
+ reg = <0x1417c 0x14>;
+ };
edma0: edma at 0 {
compatible = "ti,edma3-tpcc";
/* eDMA3 CC0: 0x01c0 0000 - 0x01c0 7fff */
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 05/17] ARM: DTS: da850: Add usb phy node
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: David Lechner <david@lechnology.com>
Add a node for the new usb phy driver.
Signed-off-by: David Lechner <david@lechnology.com>
---
arch/arm/boot/dts/da850.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 6bbf20d..33fcdce 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -376,6 +376,11 @@
>;
status = "disabled";
};
+ usb_phy: usb-phy {
+ compatible = "ti,da830-usb-phy";
+ #phy-cells = <1>;
+ status = "disabled";
+ };
gpio: gpio at 226000 {
compatible = "ti,dm6441-gpio";
gpio-controller;
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 06/17] ARM: davinci: da8xx: Fix some redefined symbol warnings
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Alexandre Bailon <abailon@baylibre.com>
Some macro for DA8xx CFGCHIP are defined in usb-davinci.h,
but da8xx-cfgchip.h intend to replace them.
The usb-da8xx.c is using both headers, causing redefined symbol warnings.
Remove the old macros.
Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
---
include/linux/platform_data/usb-davinci.h | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/include/linux/platform_data/usb-davinci.h b/include/linux/platform_data/usb-davinci.h
index e0bc4ab..0926e99 100644
--- a/include/linux/platform_data/usb-davinci.h
+++ b/include/linux/platform_data/usb-davinci.h
@@ -11,29 +11,6 @@
#ifndef __ASM_ARCH_USB_H
#define __ASM_ARCH_USB_H
-/* DA8xx CFGCHIP2 (USB 2.0 PHY Control) register bits */
-#define CFGCHIP2_PHYCLKGD (1 << 17)
-#define CFGCHIP2_VBUSSENSE (1 << 16)
-#define CFGCHIP2_RESET (1 << 15)
-#define CFGCHIP2_OTGMODE (3 << 13)
-#define CFGCHIP2_NO_OVERRIDE (0 << 13)
-#define CFGCHIP2_FORCE_HOST (1 << 13)
-#define CFGCHIP2_FORCE_DEVICE (2 << 13)
-#define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13)
-#define CFGCHIP2_USB1PHYCLKMUX (1 << 12)
-#define CFGCHIP2_USB2PHYCLKMUX (1 << 11)
-#define CFGCHIP2_PHYPWRDN (1 << 10)
-#define CFGCHIP2_OTGPWRDN (1 << 9)
-#define CFGCHIP2_DATPOL (1 << 8)
-#define CFGCHIP2_USB1SUSPENDM (1 << 7)
-#define CFGCHIP2_PHY_PLLON (1 << 6) /* override PLL suspend */
-#define CFGCHIP2_SESENDEN (1 << 5) /* Vsess_end comparator */
-#define CFGCHIP2_VBDTCTEN (1 << 4) /* Vbus comparator */
-#define CFGCHIP2_REFFREQ (0xf << 0)
-#define CFGCHIP2_REFFREQ_12MHZ (1 << 0)
-#define CFGCHIP2_REFFREQ_24MHZ (2 << 0)
-#define CFGCHIP2_REFFREQ_48MHZ (3 << 0)
-
struct da8xx_ohci_root_hub;
typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub,
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 07/17] ARM: davinci: da8xx: Enable the usb20 "per" clk on phy_clk_enable
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
While probing ochi phy with usb20 phy as a parent clock for usb11_phy,
the usb20_phy clock enable would time out. This is because the usb20
module clock needs to enabled while trying to lock the usb20_phy PLL.
Call clk enable and get for the usb20 peripheral before trying to
enable the phy PLL.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/usb-da8xx.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index 9e41a7f..982e105 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -53,11 +53,19 @@ int __init da8xx_register_usb_refclkin(int rate)
static void usb20_phy_clk_enable(struct clk *clk)
{
+ struct clk *usb20_clk;
u32 val;
u32 timeout = 500000; /* 500 msec */
val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ usb20_clk = clk_get(NULL, "usb20");
+ if (IS_ERR(usb20_clk)) {
+ pr_err("could not get usb20 clk\n");
+ return;
+ }
+
+ clk_prepare_enable(usb20_clk);
/*
* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1
* host may use the PLL clock without USB 2.0 OTG being used.
@@ -70,11 +78,14 @@ static void usb20_phy_clk_enable(struct clk *clk)
while (--timeout) {
val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
if (val & CFGCHIP2_PHYCLKGD)
- return;
+ goto done;
udelay(1);
}
pr_err("Timeout waiting for USB 2.0 PHY clock good.\n");
+done:
+ clk_disable_unprepare(usb20_clk);
+ clk_put(usb20_clk);
}
static void usb20_phy_clk_disable(struct clk *clk)
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 08/17] ARM: davinci: hawk: add full constraints for ohci plat boot
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
The phy framework requests an optional "phy" regulator. If it does
not find one, it returns -EPROBE_DEFER. In the case of non-DT based boot
for the omap138-lcdk board, this would prevent the usb11 phy to probe
correctly and ohci would not enumerate.
By calling "regulator_has_full_constraints", An error would be returned
instead of DEFER for the "optional" regulator, and the probe of
the phy driver can continue normally without a regulator.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 3 +++
arch/arm/mach-davinci/board-omapl138-hawk.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index c62766e..b33fc6b 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -26,6 +26,7 @@
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
#include <linux/platform_data/spi-davinci.h>
+#include <linux/regulator/machine.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -631,6 +632,8 @@ static __init void da830_evm_init(void)
ret = da8xx_register_spi_bus(0, ARRAY_SIZE(da830evm_spi_info));
if (ret)
pr_warn("%s: spi 0 registration failed: %d\n", __func__, ret);
+
+ regulator_has_full_constraints();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index c5cb8d9..c3ab7ea 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -14,6 +14,7 @@
#include <linux/console.h>
#include <linux/gpio.h>
#include <linux/platform_data/gpio-davinci.h>
+#include <linux/regulator/machine.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -328,6 +329,8 @@ static __init void omapl138_hawk_init(void)
if (ret)
pr_warn("%s: dsp/rproc registration failed: %d\n",
__func__, ret);
+
+ regulator_has_full_constraints();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 09/17] regulator: fixed: Add over current event
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
Some regulator supplies have an over-current pin that is
activated when the hw detects an over current condition.
When this happens, the hardware enters a current limited
mode.
Extend the fixed regulator driver with the ability
to handle irq's from the over-current pin and report
an over current event to the consumers via a regulator
notifier. Also, add device tree bindings to allow to
pass a gpio for over current monitoring.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
.../bindings/regulator/fixed-regulator.txt | 4 ++
drivers/regulator/fixed.c | 64 ++++++++++++++++++++++
include/linux/regulator/consumer.h | 5 ++
include/linux/regulator/fixed.h | 3 +
4 files changed, 76 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
index 4fae41d..d20bf67 100644
--- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -11,6 +11,8 @@ If this property is missing, the default assumed is Active low.
- gpio-open-drain: GPIO is open drain type.
If this property is missing then default assumption is false.
-vin-supply: Input supply name.
+- oc-gpio: Input gpio that signals an over current condition
+- oc-active-high: The polarity of the over current pin is high
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
@@ -26,9 +28,11 @@ Example:
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio1 16 0>;
+ oc-gpio = <&gpio1 18 0>;
startup-delay-us = <70000>;
enable-active-high;
regulator-boot-on;
gpio-open-drain;
+ oc-active-high;
vin-supply = <&parent_reg>;
};
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 988a747..e7964bb 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -30,10 +30,14 @@
#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/interrupt.h>
struct fixed_voltage_data {
struct regulator_desc desc;
struct regulator_dev *dev;
+ int oc_gpio;
+ unsigned has_oc_gpio:1;
+ unsigned oc_high:1;
};
@@ -82,6 +86,14 @@ struct fixed_voltage_data {
if ((config->gpio < 0) && (config->gpio != -ENOENT))
return ERR_PTR(config->gpio);
+ config->oc_gpio = of_get_named_gpio(np, "oc-gpio", 0);
+ if (config->oc_gpio >= 0)
+ config->has_oc_gpio = true;
+ else if (config->oc_gpio != -ENOENT)
+ return ERR_PTR(config->oc_gpio);
+
+ config->oc_high = of_property_read_bool(np, "oc-active-high");
+
of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
config->enable_high = of_property_read_bool(np, "enable-active-high");
@@ -94,7 +106,34 @@ struct fixed_voltage_data {
return config;
}
+static irqreturn_t reg_fixed_overcurrent_irq(int irq, void *data)
+{
+ struct fixed_voltage_data *drvdata = data;
+
+ regulator_notifier_call_chain(drvdata->dev,
+ REGULATOR_EVENT_OVER_CURRENT, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int reg_fixed_get_mode(struct regulator_dev *rdev)
+{
+ struct fixed_voltage_data *drvdata = rdev_get_drvdata(rdev);
+ unsigned int ret = REGULATOR_MODE_NORMAL;
+ int oc_value;
+
+ if (!drvdata->has_oc_gpio)
+ return ret;
+
+ oc_value = gpio_get_value(drvdata->oc_gpio);
+ if ((oc_value && drvdata->oc_high) || (!oc_value && !drvdata->oc_high))
+ ret = REGULATOR_MODE_OVERCURRENT;
+
+ return ret;
+}
+
static struct regulator_ops fixed_voltage_ops = {
+ .get_mode = reg_fixed_get_mode,
};
static int reg_fixed_voltage_probe(struct platform_device *pdev)
@@ -175,6 +214,31 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
cfg.driver_data = drvdata;
cfg.of_node = pdev->dev.of_node;
+ if (config->has_oc_gpio && gpio_is_valid(config->oc_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev,
+ config->oc_gpio,
+ GPIOF_DIR_IN, "oc_gpio");
+ if (ret) {
+ pr_err("Failed to request gpio: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev,
+ gpio_to_irq(config->oc_gpio), NULL,
+ reg_fixed_overcurrent_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "over_current", drvdata);
+ if (ret) {
+ pr_err("Failed to request irq: %d\n", ret);
+ return ret;
+ }
+
+ drvdata->oc_gpio = config->oc_gpio;
+ drvdata->oc_high = config->oc_high;
+ drvdata->has_oc_gpio = config->has_oc_gpio;
+ }
+
drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
&cfg);
if (IS_ERR(drvdata->dev)) {
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 6921082..9269217 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -74,6 +74,10 @@
* the most noisy and may not be able to handle fast load
* switching.
*
+ * OVERCURRENT Regulator has detected an overcurrent condition, and
+ * may be limiting the supply output.
+ *
+ *
* NOTE: Most regulators will only support a subset of these modes. Some
* will only just support NORMAL.
*
@@ -84,6 +88,7 @@
#define REGULATOR_MODE_NORMAL 0x2
#define REGULATOR_MODE_IDLE 0x4
#define REGULATOR_MODE_STANDBY 0x8
+#define REGULATOR_MODE_OVERCURRENT 0x10
/*
* Regulator notifier events.
diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h
index 48918be..79357be 100644
--- a/include/linux/regulator/fixed.h
+++ b/include/linux/regulator/fixed.h
@@ -50,10 +50,13 @@ struct fixed_voltage_config {
const char *input_supply;
int microvolts;
int gpio;
+ int oc_gpio;
unsigned startup_delay;
unsigned gpio_is_open_drain:1;
unsigned enable_high:1;
unsigned enabled_at_boot:1;
+ unsigned has_oc_gpio:1;
+ unsigned oc_high:1;
struct regulator_init_data *init_data;
};
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 10/17] USB: da8xx: use flag instead of bitmask for over current change
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
The da8xx ohci has only one port connected. In hub_control we
check that the port is 1, or else we bail out early. There is no point
in passing as argument the port number, if we know, and check that it
will always be 1.
Simplify functions and callbacks, by removing the port parameter, and
converting the over current indicatior change form a mask to a flag.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 8 ++++----
arch/arm/mach-davinci/board-omapl138-hawk.c | 8 ++++----
drivers/usb/host/ohci-da8xx.c | 29 ++++++++++++++---------------
include/linux/platform_data/usb-davinci.h | 9 ++++-----
4 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index b33fc6b..d12fcf5 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -50,18 +50,18 @@
static da8xx_ocic_handler_t da830_evm_usb_ocic_handler;
-static int da830_evm_usb_set_power(unsigned port, int on)
+static int da830_evm_usb_set_power(int on)
{
gpio_set_value(ON_BD_USB_DRV, on);
return 0;
}
-static int da830_evm_usb_get_power(unsigned port)
+static int da830_evm_usb_get_power(void)
{
return gpio_get_value(ON_BD_USB_DRV);
}
-static int da830_evm_usb_get_oci(unsigned port)
+static int da830_evm_usb_get_oci(void)
{
return !gpio_get_value(ON_BD_USB_OVC);
}
@@ -100,7 +100,7 @@ static int da830_evm_usb_ocic_notify(da8xx_ocic_handler_t handler)
static irqreturn_t da830_evm_usb_ocic_irq(int irq, void *dev_id)
{
- da830_evm_usb_ocic_handler(&da830_evm_usb11_pdata, 1);
+ da830_evm_usb_ocic_handler(&da830_evm_usb11_pdata);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index c3ab7ea..1d31f45 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -189,18 +189,18 @@ static __init void omapl138_hawk_mmc_init(void)
-1
};
-static int hawk_usb_set_power(unsigned port, int on)
+static int hawk_usb_set_power(int on)
{
gpio_set_value(DA850_USB1_VBUS_PIN, on);
return 0;
}
-static int hawk_usb_get_power(unsigned port)
+static int hawk_usb_get_power(void)
{
return gpio_get_value(DA850_USB1_VBUS_PIN);
}
-static int hawk_usb_get_oci(unsigned port)
+static int hawk_usb_get_oci(void)
{
return !gpio_get_value(DA850_USB1_OC_PIN);
}
@@ -237,7 +237,7 @@ static int hawk_usb_ocic_notify(da8xx_ocic_handler_t handler)
static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id)
{
- hawk_usb_ocic_handler(&omapl138_hawk_usb11_pdata, 1);
+ hawk_usb_ocic_handler(&omapl138_hawk_usb11_pdata);
return IRQ_HANDLED;
}
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 3656d7c..e98066d 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -25,8 +25,8 @@
static struct clk *usb11_clk;
static struct phy *usb11_phy;
-/* Over-current indicator change bitmask */
-static volatile u16 ocic_mask;
+/* Over-current indicator change flag */
+static int ocic_flag;
static int ohci_da8xx_enable(void)
{
@@ -64,14 +64,13 @@ static void ohci_da8xx_disable(void)
/*
* Handle the port over-current indicator change.
*/
-static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
- unsigned port)
+static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub)
{
- ocic_mask |= 1 << port;
+ ocic_flag = 1;
/* Once over-current is detected, the port needs to be powered down */
- if (hub->get_oci(port) > 0)
- hub->set_power(port, 0);
+ if (hub->get_oci() > 0)
+ hub->set_power(0);
}
static int ohci_da8xx_init(struct usb_hcd *hcd)
@@ -147,8 +146,8 @@ static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
{
int length = ohci_hub_status_data(hcd, buf);
- /* See if we have OCIC bit set on port 1 */
- if (ocic_mask & (1 << 1)) {
+ /* See if we have OCIC flag set */
+ if (ocic_flag) {
dev_dbg(hcd->self.controller, "over-current indicator change "
"on port 1\n");
@@ -181,15 +180,15 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
/* The port power status (PPS) bit defaults to 1 */
- if (hub->get_power && hub->get_power(wIndex) == 0)
+ if (hub->get_power && hub->get_power() == 0)
temp &= ~RH_PS_PPS;
/* The port over-current indicator (POCI) bit is always 0 */
- if (hub->get_oci && hub->get_oci(wIndex) > 0)
+ if (hub->get_oci && hub->get_oci() > 0)
temp |= RH_PS_POCI;
/* The over-current indicator change (OCIC) bit is 0 too */
- if (ocic_mask & (1 << wIndex))
+ if (ocic_flag)
temp |= RH_PS_OCIC;
put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
@@ -213,16 +212,16 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (!hub->set_power)
return -EPIPE;
- return hub->set_power(wIndex, temp) ? -EPIPE : 0;
+ return hub->set_power(temp) ? -EPIPE : 0;
case USB_PORT_FEAT_C_OVER_CURRENT:
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex,
"C_OVER_CURRENT");
if (temp)
- ocic_mask |= 1 << wIndex;
+ ocic_flag = 1;
else
- ocic_mask &= ~(1 << wIndex);
+ ocic_flag = 0;
return 0;
}
}
diff --git a/include/linux/platform_data/usb-davinci.h b/include/linux/platform_data/usb-davinci.h
index 0926e99..3217fbe 100644
--- a/include/linux/platform_data/usb-davinci.h
+++ b/include/linux/platform_data/usb-davinci.h
@@ -13,17 +13,16 @@
struct da8xx_ohci_root_hub;
-typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub,
- unsigned port);
+typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub);
/* Passed as the platform data to the OHCI driver */
struct da8xx_ohci_root_hub {
/* Switch the port power on/off */
- int (*set_power)(unsigned port, int on);
+ int (*set_power)(int on);
/* Read the port power status */
- int (*get_power)(unsigned port);
+ int (*get_power)(void);
/* Read the port over-current indicator */
- int (*get_oci)(unsigned port);
+ int (*get_oci)(void);
/* Over-current indicator change notification (pass NULL to disable) */
int (*ocic_notify)(da8xx_ocic_handler_t handler);
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 11/17] USB: OHCI: make ohci-da8xx a separate driver
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Manjunath Goudar <manjunath.goudar@linaro.org>
Separate the Davinci OHCI host controller driver from ohci-hcd
host code so that it can be built as a separate driver module.
This work is part of enabling multi-platform kernels on ARM;
it would be nice to have in 3.11.
Signed-off-by: Manjunath Goudar <manjunath.goudar@linaro.org>
---
drivers/usb/host/Kconfig | 2 +-
drivers/usb/host/Makefile | 1 +
drivers/usb/host/ohci-da8xx.c | 185 +++++++++++++++++-------------------------
drivers/usb/host/ohci-hcd.c | 18 ----
4 files changed, 76 insertions(+), 130 deletions(-)
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 83b6cec..642c6fe8 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -479,7 +479,7 @@ config USB_OHCI_HCD_OMAP3
OMAP3 and later chips.
config USB_OHCI_HCD_DAVINCI
- bool "OHCI support for TI DaVinci DA8xx"
+ tristate "OHCI support for TI DaVinci DA8xx"
depends on ARCH_DAVINCI_DA8XX
depends on USB_OHCI_HCD=y
select PHY_DA8XX_USB
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 6ef785b..2644537 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_USB_OHCI_HCD_AT91) += ohci-at91.o
obj-$(CONFIG_USB_OHCI_HCD_S3C2410) += ohci-s3c2410.o
obj-$(CONFIG_USB_OHCI_HCD_LPC32XX) += ohci-nxp.o
obj-$(CONFIG_USB_OHCI_HCD_PXA27X) += ohci-pxa27x.o
+obj-$(CONFIG_USB_OHCI_HCD_DAVINCI) += ohci-da8xx.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index e98066d..5585d9e 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -11,16 +11,31 @@
* kind, whether express or implied.
*/
+#include <linux/clk.h>
+#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/clk.h>
#include <linux/phy/phy.h>
#include <linux/platform_data/usb-davinci.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <asm/unaligned.h>
-#ifndef CONFIG_ARCH_DAVINCI_DA8XX
-#error "This file is DA8xx bus glue. Define CONFIG_ARCH_DAVINCI_DA8XX."
-#endif
+#include "ohci.h"
+
+#define DRIVER_DESC "OHCI DA8XX driver"
+
+static const char hcd_name[] = "ohci-da8xx";
+
+static struct hc_driver __read_mostly ohci_da8xx_hc_driver;
+
+static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength);
+static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf);
static struct clk *usb11_clk;
static struct phy *usb11_phy;
@@ -73,7 +88,7 @@ static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub)
hub->set_power(0);
}
-static int ohci_da8xx_init(struct usb_hcd *hcd)
+static int ohci_da8xx_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
@@ -93,7 +108,7 @@ static int ohci_da8xx_init(struct usb_hcd *hcd)
*/
ohci->num_ports = 1;
- result = ohci_init(ohci);
+ result = ohci_setup(hcd);
if (result < 0) {
ohci_da8xx_disable();
return result;
@@ -121,30 +136,12 @@ static int ohci_da8xx_init(struct usb_hcd *hcd)
return result;
}
-static void ohci_da8xx_stop(struct usb_hcd *hcd)
-{
- ohci_stop(hcd);
- ohci_da8xx_disable();
-}
-
-static int ohci_da8xx_start(struct usb_hcd *hcd)
-{
- struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- int result;
-
- result = ohci_run(ohci);
- if (result < 0)
- ohci_da8xx_stop(hcd);
-
- return result;
-}
-
/*
* Update the status data from the hub with the over-current indicator change.
*/
static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
{
- int length = ohci_hub_status_data(hcd, buf);
+ int length = orig_ohci_hub_status_data(hcd, buf);
/* See if we have OCIC flag set */
if (ocic_flag) {
@@ -226,66 +223,13 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
}
- return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+ return orig_ohci_hub_control(hcd, typeReq, wValue,
+ wIndex, buf, wLength);
}
-static const struct hc_driver ohci_da8xx_hc_driver = {
- .description = hcd_name,
- .product_desc = "DA8xx OHCI",
- .hcd_priv_size = sizeof(struct ohci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
-
- /*
- * basic lifecycle operations
- */
- .reset = ohci_da8xx_init,
- .start = ohci_da8xx_start,
- .stop = ohci_da8xx_stop,
- .shutdown = ohci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ohci_urb_enqueue,
- .urb_dequeue = ohci_urb_dequeue,
- .endpoint_disable = ohci_endpoint_disable,
-
- /*
- * scheduling support
- */
- .get_frame_number = ohci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ohci_da8xx_hub_status_data,
- .hub_control = ohci_da8xx_hub_control,
-
-#ifdef CONFIG_PM
- .bus_suspend = ohci_bus_suspend,
- .bus_resume = ohci_bus_resume,
-#endif
- .start_port_reset = ohci_start_port_reset,
-};
-
/*-------------------------------------------------------------------------*/
-
-/**
- * usb_hcd_da8xx_probe - initialize DA8xx-based HCDs
- * Context: !in_interrupt()
- *
- * Allocates basic resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- */
-static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
- struct platform_device *pdev)
+static int ohci_da8xx_probe(struct platform_device *pdev)
{
struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
struct usb_hcd *hcd;
@@ -295,6 +239,11 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
if (hub == NULL)
return -ENODEV;
+ hcd = usb_create_hcd(&ohci_da8xx_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
usb11_clk = devm_clk_get(&pdev->dev, "usb11");
if (IS_ERR(usb11_clk)) {
if (PTR_ERR(usb11_clk) != -EPROBE_DEFER)
@@ -309,9 +258,6 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
return PTR_ERR(usb11_phy);
}
- hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
- if (!hcd)
- return -ENOMEM;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, mem);
@@ -323,13 +269,12 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
hcd->rsrc_start = mem->start;
hcd->rsrc_len = resource_size(mem);
- ohci_hcd_init(hcd_to_ohci(hcd));
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
error = -ENODEV;
goto err;
}
+
error = usb_add_hcd(hcd, irq, 0);
if (error)
goto err;
@@ -348,35 +293,14 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
return error;
}
-/**
- * usb_hcd_da8xx_remove - shutdown processing for DA8xx-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_da8xx_probe(), first invoking
- * the HCD's stop() method. It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
- */
-static inline void
-usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+static int ohci_da8xx_remove(struct platform_device *pdev)
{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
hub->ocic_notify(NULL);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
-}
-
-static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev)
-{
- return usb_hcd_da8xx_probe(&ohci_da8xx_hc_driver, dev);
-}
-
-static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(dev);
-
- usb_hcd_da8xx_remove(hcd, dev);
return 0;
}
@@ -426,12 +350,16 @@ static int ohci_da8xx_resume(struct platform_device *dev)
}
#endif
+static const struct ohci_driver_overrides da8xx_overrides __initconst = {
+ .reset = ohci_da8xx_reset
+};
+
/*
* Driver definition to register with platform structure.
*/
static struct platform_driver ohci_hcd_da8xx_driver = {
- .probe = ohci_hcd_da8xx_drv_probe,
- .remove = ohci_hcd_da8xx_drv_remove,
+ .probe = ohci_da8xx_probe,
+ .remove = ohci_da8xx_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_da8xx_suspend,
@@ -442,4 +370,39 @@ static int ohci_da8xx_resume(struct platform_device *dev)
},
};
+static int __init ohci_da8xx_init(void)
+{
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+ ohci_init_driver(&ohci_da8xx_hc_driver, &da8xx_overrides);
+
+ /*
+ * The Davinci da8xx HW has some unusual quirks, which require
+ * da8xx-specific workarounds. We override certain hc_driver
+ * functions here to achieve that. We explicitly do not enhance
+ * ohci_driver_overrides to allow this more easily, since this
+ * is an unusual case, and we don't want to encourage others to
+ * override these functions by making it too easy.
+ */
+
+ orig_ohci_hub_control = ohci_da8xx_hc_driver.hub_control;
+ orig_ohci_hub_status_data = ohci_da8xx_hc_driver.hub_status_data;
+
+ ohci_da8xx_hc_driver.hub_status_data = ohci_da8xx_hub_status_data;
+ ohci_da8xx_hc_driver.hub_control = ohci_da8xx_hub_control;
+
+ return platform_driver_register(&ohci_hcd_da8xx_driver);
+}
+module_init(ohci_da8xx_init);
+
+static void __exit ohci_da8xx_cleanup(void)
+{
+ platform_driver_unregister(&ohci_hcd_da8xx_driver);
+}
+module_exit(ohci_da8xx_cleanup);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ohci");
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 1700908..8de174a 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1219,11 +1219,6 @@ void ohci_init_driver(struct hc_driver *drv,
#define SA1111_DRIVER ohci_hcd_sa1111_driver
#endif
-#ifdef CONFIG_USB_OHCI_HCD_DAVINCI
-#include "ohci-da8xx.c"
-#define DAVINCI_PLATFORM_DRIVER ohci_hcd_da8xx_driver
-#endif
-
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
#include "ohci-ppc-of.c"
#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
@@ -1303,19 +1298,9 @@ static int __init ohci_hcd_mod_init(void)
goto error_tmio;
#endif
-#ifdef DAVINCI_PLATFORM_DRIVER
- retval = platform_driver_register(&DAVINCI_PLATFORM_DRIVER);
- if (retval < 0)
- goto error_davinci;
-#endif
-
return retval;
/* Error path */
-#ifdef DAVINCI_PLATFORM_DRIVER
- platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER);
- error_davinci:
-#endif
#ifdef TMIO_OHCI_DRIVER
platform_driver_unregister(&TMIO_OHCI_DRIVER);
error_tmio:
@@ -1351,9 +1336,6 @@ static int __init ohci_hcd_mod_init(void)
static void __exit ohci_hcd_mod_exit(void)
{
-#ifdef DAVINCI_PLATFORM_DRIVER
- platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER);
-#endif
#ifdef TMIO_OHCI_DRIVER
platform_driver_unregister(&TMIO_OHCI_DRIVER);
#endif
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 12/17] USB: ochi-da8xx: Use a regulator for vbus/overcurrent
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
Currently, the da8xx ohci driver uses a set of gpios and callbacks in
board files to handle vbus and overcurrent irqs form the power supply.
However, this does not play nice when moving to a DT based boot were
we wont have board files.
Instead of requesting and handling the gpio, use the regulator framework
to take care of enabling and disabling vbus power. This has the benefit
that we dont need to pass any more platform data to the driver:
These will be handled by the regulator framework:
set_power -> regulator_enable/regulator_disable
get_power -> regulator_is_enabled
get_oci -> regulator_get_mode
ocic_notify -> regulator notification
We can keep the default potpgt and use the regulator start delay instead:
potpgt -> regulator startup delay time
The hawk board does not have a GPIO/OVERCURRENT gpio to control vbus,
(they should not have been decleared/reserved) so, just remove those
definitions from the hwk board file.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/board-da830-evm.c | 97 ++++++++----------------
arch/arm/mach-davinci/board-omapl138-hawk.c | 96 +-----------------------
arch/arm/mach-davinci/include/mach/da8xx.h | 2 +-
arch/arm/mach-davinci/usb-da8xx.c | 3 +-
drivers/usb/host/ohci-da8xx.c | 111 ++++++++++++++++++----------
include/linux/platform_data/usb-davinci.h | 19 -----
6 files changed, 105 insertions(+), 223 deletions(-)
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index d12fcf5..d6f9f8a 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -27,6 +27,7 @@
#include <linux/platform_data/mtd-davinci-aemif.h>
#include <linux/platform_data/spi-davinci.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -48,61 +49,35 @@
-1
};
-static da8xx_ocic_handler_t da830_evm_usb_ocic_handler;
+static struct regulator_consumer_supply usb_ohci_consumer_supply =
+ REGULATOR_SUPPLY("vbus", "ohci");
-static int da830_evm_usb_set_power(int on)
-{
- gpio_set_value(ON_BD_USB_DRV, on);
- return 0;
-}
-
-static int da830_evm_usb_get_power(void)
-{
- return gpio_get_value(ON_BD_USB_DRV);
-}
-
-static int da830_evm_usb_get_oci(void)
-{
- return !gpio_get_value(ON_BD_USB_OVC);
-}
-
-static irqreturn_t da830_evm_usb_ocic_irq(int, void *);
-
-static int da830_evm_usb_ocic_notify(da8xx_ocic_handler_t handler)
-{
- int irq = gpio_to_irq(ON_BD_USB_OVC);
- int error = 0;
-
- if (handler != NULL) {
- da830_evm_usb_ocic_handler = handler;
-
- error = request_irq(irq, da830_evm_usb_ocic_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "OHCI over-current indicator", NULL);
- if (error)
- pr_err("%s: could not request IRQ to watch over-current indicator changes\n",
- __func__);
- } else
- free_irq(irq, NULL);
-
- return error;
-}
-
-static struct da8xx_ohci_root_hub da830_evm_usb11_pdata = {
- .set_power = da830_evm_usb_set_power,
- .get_power = da830_evm_usb_get_power,
- .get_oci = da830_evm_usb_get_oci,
- .ocic_notify = da830_evm_usb_ocic_notify,
+static struct regulator_init_data usb_ohci_initdata = {
+ .consumer_supplies = &usb_ohci_consumer_supply,
+ .num_consumer_supplies = 1,
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+};
- /* TPS2065 switch @ 5V */
- .potpgt = (3 + 1) / 2, /* 3 ms max */
+static struct fixed_voltage_config usb_ohci_config = {
+ .supply_name = "vbus",
+ .microvolts = 5000000,
+ .gpio = ON_BD_USB_DRV,
+ .oc_gpio = ON_BD_USB_OVC,
+ .has_oc_gpio = 1,
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &usb_ohci_initdata,
};
-static irqreturn_t da830_evm_usb_ocic_irq(int irq, void *dev_id)
-{
- da830_evm_usb_ocic_handler(&da830_evm_usb11_pdata);
- return IRQ_HANDLED;
-}
+static struct platform_device da8xx_usb11_regulator = {
+ .name = "reg-fixed-voltage",
+ .id = 0,
+ .dev = {
+ .platform_data = &usb_ohci_config,
+ },
+};
static __init void da830_evm_usb_init(void)
{
@@ -144,23 +119,11 @@ static __init void da830_evm_usb_init(void)
return;
}
- ret = gpio_request(ON_BD_USB_DRV, "ON_BD_USB_DRV");
- if (ret) {
- pr_err("%s: failed to request GPIO for USB 1.1 port power control: %d\n",
- __func__, ret);
- return;
- }
- gpio_direction_output(ON_BD_USB_DRV, 0);
-
- ret = gpio_request(ON_BD_USB_OVC, "ON_BD_USB_OVC");
- if (ret) {
- pr_err("%s: failed to request GPIO for USB 1.1 port over-current indicator: %d\n",
- __func__, ret);
- return;
- }
- gpio_direction_input(ON_BD_USB_OVC);
+ ret = platform_device_register(&da8xx_usb11_regulator);
+ if (ret)
+ pr_warn("fail to add ohci regulator\n");
- ret = da8xx_register_usb11(&da830_evm_usb11_pdata);
+ ret = da8xx_register_usb11();
if (ret)
pr_warn("%s: USB 1.1 registration failed: %d\n", __func__, ret);
}
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 1d31f45..2df34cb 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -28,9 +28,6 @@
#define DA850_HAWK_MMCSD_CD_PIN GPIO_TO_PIN(3, 12)
#define DA850_HAWK_MMCSD_WP_PIN GPIO_TO_PIN(3, 13)
-#define DA850_USB1_VBUS_PIN GPIO_TO_PIN(2, 4)
-#define DA850_USB1_OC_PIN GPIO_TO_PIN(6, 13)
-
static short omapl138_hawk_mii_pins[] __initdata = {
DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
@@ -181,76 +178,10 @@ static __init void omapl138_hawk_mmc_init(void)
gpio_free(DA850_HAWK_MMCSD_CD_PIN);
}
-static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id);
-static da8xx_ocic_handler_t hawk_usb_ocic_handler;
-
-static const short da850_hawk_usb11_pins[] = {
- DA850_GPIO2_4, DA850_GPIO6_13,
- -1
-};
-
-static int hawk_usb_set_power(int on)
-{
- gpio_set_value(DA850_USB1_VBUS_PIN, on);
- return 0;
-}
-
-static int hawk_usb_get_power(void)
-{
- return gpio_get_value(DA850_USB1_VBUS_PIN);
-}
-
-static int hawk_usb_get_oci(void)
-{
- return !gpio_get_value(DA850_USB1_OC_PIN);
-}
-
-static int hawk_usb_ocic_notify(da8xx_ocic_handler_t handler)
-{
- int irq = gpio_to_irq(DA850_USB1_OC_PIN);
- int error = 0;
-
- if (handler != NULL) {
- hawk_usb_ocic_handler = handler;
-
- error = request_irq(irq, omapl138_hawk_usb_ocic_irq,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING,
- "OHCI over-current indicator", NULL);
- if (error)
- pr_err("%s: could not request IRQ to watch "
- "over-current indicator changes\n", __func__);
- } else {
- free_irq(irq, NULL);
- }
- return error;
-}
-
-static struct da8xx_ohci_root_hub omapl138_hawk_usb11_pdata = {
- .set_power = hawk_usb_set_power,
- .get_power = hawk_usb_get_power,
- .get_oci = hawk_usb_get_oci,
- .ocic_notify = hawk_usb_ocic_notify,
- /* TPS2087 switch @ 5V */
- .potpgt = (3 + 1) / 2, /* 3 ms max */
-};
-
-static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id)
-{
- hawk_usb_ocic_handler(&omapl138_hawk_usb11_pdata);
- return IRQ_HANDLED;
-}
-
static __init void omapl138_hawk_usb_init(void)
{
int ret;
- ret = davinci_cfg_reg_list(da850_hawk_usb11_pins);
- if (ret) {
- pr_warn("%s: USB 1.1 PinMux setup failed: %d\n", __func__, ret);
- return;
- }
-
/* USB_REFCLKIN is not used. */
ret = da8xx_register_usb20_phy_clk(false);
if (ret)
@@ -266,34 +197,11 @@ static __init void omapl138_hawk_usb_init(void)
pr_warn("%s: USB PHY registration failed: %d\n",
__func__, ret);
- ret = gpio_request_one(DA850_USB1_VBUS_PIN,
- GPIOF_DIR_OUT, "USB1 VBUS");
- if (ret < 0) {
- pr_err("%s: failed to request GPIO for USB 1.1 port "
- "power control: %d\n", __func__, ret);
- return;
- }
-
- ret = gpio_request_one(DA850_USB1_OC_PIN,
- GPIOF_DIR_IN, "USB1 OC");
- if (ret < 0) {
- pr_err("%s: failed to request GPIO for USB 1.1 port "
- "over-current indicator: %d\n", __func__, ret);
- goto usb11_setup_oc_fail;
- }
-
- ret = da8xx_register_usb11(&omapl138_hawk_usb11_pdata);
- if (ret) {
+ ret = da8xx_register_usb11();
+ if (ret)
pr_warn("%s: USB 1.1 registration failed: %d\n", __func__, ret);
- goto usb11_setup_fail;
- }
return;
-
-usb11_setup_fail:
- gpio_free(DA850_USB1_OC_PIN);
-usb11_setup_oc_fail:
- gpio_free(DA850_USB1_VBUS_PIN);
}
static __init void omapl138_hawk_init(void)
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 38d932e..93d2db3 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -94,7 +94,7 @@
int da8xx_register_usb11_phy_clk(bool use_usb_refclkin);
int da8xx_register_usb_phy(void);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
-int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
+int da8xx_register_usb11(void);
int da8xx_register_emac(void);
int da8xx_register_uio_pruss(void);
int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
diff --git a/arch/arm/mach-davinci/usb-da8xx.c b/arch/arm/mach-davinci/usb-da8xx.c
index 982e105..7a9af216 100644
--- a/arch/arm/mach-davinci/usb-da8xx.c
+++ b/arch/arm/mach-davinci/usb-da8xx.c
@@ -337,8 +337,7 @@ int __init da8xx_register_usb20(unsigned int mA, unsigned int potpgt)
.resource = da8xx_usb11_resources,
};
-int __init da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata)
+int __init da8xx_register_usb11(void)
{
- da8xx_usb11_device.dev.platform_data = pdata;
return platform_device_register(&da8xx_usb11_device);
}
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 5585d9e..f4bda4d 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -39,6 +39,8 @@ static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq,
static struct clk *usb11_clk;
static struct phy *usb11_phy;
+static struct regulator *vbus_reg;
+struct notifier_block nb;
/* Over-current indicator change flag */
static int ocic_flag;
@@ -76,22 +78,57 @@ static void ohci_da8xx_disable(void)
clk_disable_unprepare(usb11_clk);
}
-/*
- * Handle the port over-current indicator change.
- */
-static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub)
+static int ohci_da8xx_set_power(int on)
+{
+ int ret = 0;
+
+ if (!vbus_reg)
+ return 0;
+
+ if (on) {
+ ret = regulator_enable(vbus_reg);
+ if (ret)
+ pr_err("fail to enable regulator: %d\n", ret);
+ } else {
+ ret = regulator_disable(vbus_reg);
+ if (ret)
+ pr_err("fail to disable regulator: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static int ohci_da8xx_get_power(void)
+{
+ if (!vbus_reg)
+ return 1;
+
+ return regulator_is_enabled(vbus_reg);
+}
+
+static int ohci_da8xx_get_oci(void)
+{
+ if (regulator_get_mode(vbus_reg) == REGULATOR_MODE_OVERCURRENT)
+ return 1;
+
+ return 0;
+}
+
+static int ohci_da8xx_regulator_event(struct notifier_block *nb,
+ unsigned long event, void *data)
{
- ocic_flag = 1;
+ if (event & REGULATOR_EVENT_OVER_CURRENT) {
+ ocic_flag = 1;
+ if (ohci_da8xx_get_oci())
+ ohci_da8xx_set_power(0);
+ }
- /* Once over-current is detected, the port needs to be powered down */
- if (hub->get_oci() > 0)
- hub->set_power(0);
+ return 0;
}
static int ohci_da8xx_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int result;
u32 rh_a;
@@ -121,16 +158,14 @@ static int ohci_da8xx_reset(struct usb_hcd *hcd)
* the correct hub descriptor...
*/
rh_a = ohci_readl(ohci, &ohci->regs->roothub.a);
- if (hub->set_power) {
+
+ if (vbus_reg) {
rh_a &= ~RH_A_NPS;
rh_a |= RH_A_PSM;
- }
- if (hub->get_oci) {
rh_a &= ~RH_A_NOCP;
rh_a |= RH_A_OCPM;
}
- rh_a &= ~RH_A_POTPGT;
- rh_a |= hub->potpgt << 24;
+
ohci_writel(ohci, rh_a, &ohci->regs->roothub.a);
return result;
@@ -163,7 +198,6 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
int temp;
switch (typeReq) {
@@ -177,11 +211,11 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
/* The port power status (PPS) bit defaults to 1 */
- if (hub->get_power && hub->get_power() == 0)
+ if (ohci_da8xx_get_power() == 0)
temp &= ~RH_PS_PPS;
/* The port over-current indicator (POCI) bit is always 0 */
- if (hub->get_oci && hub->get_oci() > 0)
+ if (ohci_da8xx_get_oci() > 0)
temp |= RH_PS_POCI;
/* The over-current indicator change (OCIC) bit is 0 too */
@@ -206,19 +240,13 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex, "POWER");
- if (!hub->set_power)
- return -EPIPE;
-
- return hub->set_power(temp) ? -EPIPE : 0;
+ return ohci_da8xx_set_power(temp) ? -EPIPE : 0;
case USB_PORT_FEAT_C_OVER_CURRENT:
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex,
"C_OVER_CURRENT");
- if (temp)
- ocic_flag = 1;
- else
- ocic_flag = 0;
+ ocic_flag = temp;
return 0;
}
}
@@ -231,14 +259,10 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
static int ohci_da8xx_probe(struct platform_device *pdev)
{
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
struct usb_hcd *hcd;
struct resource *mem;
int error, irq;
- if (hub == NULL)
- return -ENODEV;
-
hcd = usb_create_hcd(&ohci_da8xx_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd)
@@ -258,6 +282,22 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
return PTR_ERR(usb11_phy);
}
+ vbus_reg = devm_regulator_get(&pdev->dev, "vbus");
+ if (IS_ERR(vbus_reg)) {
+ if (PTR_ERR(vbus_reg) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get regulator.\n");
+ return PTR_ERR(vbus_reg);
+ }
+
+ if (vbus_reg) {
+ nb.notifier_call = ohci_da8xx_regulator_event;
+ error = devm_regulator_register_notifier(vbus_reg, &nb);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Could not register regulator notifier\n");
+ return error;
+ }
+ }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, mem);
@@ -281,13 +321,7 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
device_wakeup_enable(hcd->self.controller);
- if (hub->ocic_notify) {
- error = hub->ocic_notify(ohci_da8xx_ocic_handler);
- if (!error)
- return 0;
- }
-
- usb_remove_hcd(hcd);
+ return 0;
err:
usb_put_hcd(hcd);
return error;
@@ -295,10 +329,8 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
static int ohci_da8xx_remove(struct platform_device *pdev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
- hub->ocic_notify(NULL);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -314,7 +346,6 @@ static int ohci_da8xx_suspend(struct platform_device *pdev,
bool do_wakeup = device_may_wakeup(&pdev->dev);
int ret;
-
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
diff --git a/include/linux/platform_data/usb-davinci.h b/include/linux/platform_data/usb-davinci.h
index 3217fbe..58f4be0 100644
--- a/include/linux/platform_data/usb-davinci.h
+++ b/include/linux/platform_data/usb-davinci.h
@@ -11,25 +11,6 @@
#ifndef __ASM_ARCH_USB_H
#define __ASM_ARCH_USB_H
-struct da8xx_ohci_root_hub;
-
-typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub);
-
-/* Passed as the platform data to the OHCI driver */
-struct da8xx_ohci_root_hub {
- /* Switch the port power on/off */
- int (*set_power)(int on);
- /* Read the port power status */
- int (*get_power)(void);
- /* Read the port over-current indicator */
- int (*get_oci)(void);
- /* Over-current indicator change notification (pass NULL to disable) */
- int (*ocic_notify)(da8xx_ocic_handler_t handler);
-
- /* Time from power on to power good (in 2 ms units) */
- u8 potpgt;
-};
-
void davinci_setup_usb(unsigned mA, unsigned potpgt_ms);
#endif /* ifndef __ASM_ARCH_USB_H */
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 13/17] USB: da8xx: use ohci priv data instead of globals
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
Instead of global variables, use the extra_priv_size of the ohci driver
to add a reference to driver private data.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
drivers/usb/host/ohci-da8xx.c | 135 ++++++++++++++++++++++++------------------
1 file changed, 79 insertions(+), 56 deletions(-)
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index f4bda4d..bebc3f0 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -37,60 +37,66 @@ static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq,
u16 wValue, u16 wIndex, char *buf, u16 wLength);
static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf);
-static struct clk *usb11_clk;
-static struct phy *usb11_phy;
-static struct regulator *vbus_reg;
-struct notifier_block nb;
-
-/* Over-current indicator change flag */
-static int ocic_flag;
+struct da8xx_ohci_hcd {
+ struct usb_hcd *hcd;
+ struct clk *usb11_clk;
+ struct phy *usb11_phy;
+ struct regulator *vbus_reg;
+ struct notifier_block nb;
+ int ocic_flag;
+};
+#define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
-static int ohci_da8xx_enable(void)
+static int ohci_da8xx_enable(struct usb_hcd *hcd)
{
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
int ret;
- ret = clk_prepare_enable(usb11_clk);
+ ret = clk_prepare_enable(da8xx_ohci->usb11_clk);
if (ret)
return ret;
- ret = phy_init(usb11_phy);
+ ret = phy_init(da8xx_ohci->usb11_phy);
if (ret)
goto err_phy_init;
- ret = phy_power_on(usb11_phy);
+ ret = phy_power_on(da8xx_ohci->usb11_phy);
if (ret)
goto err_phy_power_on;
return 0;
err_phy_power_on:
- phy_exit(usb11_phy);
+ phy_exit(da8xx_ohci->usb11_phy);
err_phy_init:
- clk_disable_unprepare(usb11_clk);
+ clk_disable_unprepare(da8xx_ohci->usb11_clk);
return ret;
}
-static void ohci_da8xx_disable(void)
+static void ohci_da8xx_disable(struct usb_hcd *hcd)
{
- phy_power_off(usb11_phy);
- phy_exit(usb11_phy);
- clk_disable_unprepare(usb11_clk);
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
+
+ phy_power_off(da8xx_ohci->usb11_phy);
+ phy_exit(da8xx_ohci->usb11_phy);
+ clk_disable_unprepare(da8xx_ohci->usb11_clk);
}
-static int ohci_da8xx_set_power(int on)
+static int ohci_da8xx_set_power(struct usb_hcd *hcd, int on)
{
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
int ret = 0;
- if (!vbus_reg)
+ if (!da8xx_ohci->vbus_reg)
return 0;
if (on) {
- ret = regulator_enable(vbus_reg);
+ ret = regulator_enable(da8xx_ohci->vbus_reg);
if (ret)
pr_err("fail to enable regulator: %d\n", ret);
} else {
- ret = regulator_disable(vbus_reg);
+ ret = regulator_disable(da8xx_ohci->vbus_reg);
if (ret)
pr_err("fail to disable regulator: %d\n", ret);
}
@@ -98,17 +104,22 @@ static int ohci_da8xx_set_power(int on)
return ret;
}
-static int ohci_da8xx_get_power(void)
+static int ohci_da8xx_get_power(struct usb_hcd *hcd)
{
- if (!vbus_reg)
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
+
+ if (!da8xx_ohci->vbus_reg)
return 1;
- return regulator_is_enabled(vbus_reg);
+ return regulator_is_enabled(da8xx_ohci->vbus_reg);
}
-static int ohci_da8xx_get_oci(void)
+static int ohci_da8xx_get_oci(struct usb_hcd *hcd)
{
- if (regulator_get_mode(vbus_reg) == REGULATOR_MODE_OVERCURRENT)
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
+
+ if (regulator_get_mode(da8xx_ohci->vbus_reg) ==
+ REGULATOR_MODE_OVERCURRENT)
return 1;
return 0;
@@ -117,10 +128,13 @@ static int ohci_da8xx_get_oci(void)
static int ohci_da8xx_regulator_event(struct notifier_block *nb,
unsigned long event, void *data)
{
+ struct da8xx_ohci_hcd *da8xx_ohci =
+ container_of(nb, struct da8xx_ohci_hcd, nb);
+
if (event & REGULATOR_EVENT_OVER_CURRENT) {
- ocic_flag = 1;
- if (ohci_da8xx_get_oci())
- ohci_da8xx_set_power(0);
+ da8xx_ohci->ocic_flag = 1;
+ if (ohci_da8xx_get_oci(da8xx_ohci->hcd))
+ ohci_da8xx_set_power(da8xx_ohci->hcd, 0);
}
return 0;
@@ -130,12 +144,13 @@ static int ohci_da8xx_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
int result;
u32 rh_a;
dev_dbg(dev, "starting USB controller\n");
- result = ohci_da8xx_enable();
+ result = ohci_da8xx_enable(hcd);
if (result < 0)
return result;
@@ -147,7 +162,7 @@ static int ohci_da8xx_reset(struct usb_hcd *hcd)
result = ohci_setup(hcd);
if (result < 0) {
- ohci_da8xx_disable();
+ ohci_da8xx_disable(hcd);
return result;
}
@@ -159,7 +174,7 @@ static int ohci_da8xx_reset(struct usb_hcd *hcd)
*/
rh_a = ohci_readl(ohci, &ohci->regs->roothub.a);
- if (vbus_reg) {
+ if (da8xx_ohci->vbus_reg) {
rh_a &= ~RH_A_NPS;
rh_a |= RH_A_PSM;
rh_a &= ~RH_A_NOCP;
@@ -176,10 +191,11 @@ static int ohci_da8xx_reset(struct usb_hcd *hcd)
*/
static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
{
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
int length = orig_ohci_hub_status_data(hcd, buf);
/* See if we have OCIC flag set */
- if (ocic_flag) {
+ if (da8xx_ohci->ocic_flag) {
dev_dbg(hcd->self.controller, "over-current indicator change "
"on port 1\n");
@@ -197,6 +213,7 @@ static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
+ struct da8xx_ohci_hcd *da8xx_ohci = to_da8xx_ohci(hcd);
struct device *dev = hcd->self.controller;
int temp;
@@ -211,15 +228,15 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
/* The port power status (PPS) bit defaults to 1 */
- if (ohci_da8xx_get_power() == 0)
+ if (ohci_da8xx_get_power(hcd) == 0)
temp &= ~RH_PS_PPS;
/* The port over-current indicator (POCI) bit is always 0 */
- if (ohci_da8xx_get_oci() > 0)
+ if (ohci_da8xx_get_oci(hcd) > 0)
temp |= RH_PS_POCI;
/* The over-current indicator change (OCIC) bit is 0 too */
- if (ocic_flag)
+ if (da8xx_ohci->ocic_flag)
temp |= RH_PS_OCIC;
put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
@@ -240,13 +257,13 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex, "POWER");
- return ohci_da8xx_set_power(temp) ? -EPIPE : 0;
+ return ohci_da8xx_set_power(hcd, temp) ? -EPIPE : 0;
case USB_PORT_FEAT_C_OVER_CURRENT:
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex,
"C_OVER_CURRENT");
- ocic_flag = temp;
+ da8xx_ohci->ocic_flag = temp;
return 0;
}
}
@@ -259,6 +276,7 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
static int ohci_da8xx_probe(struct platform_device *pdev)
{
+ struct da8xx_ohci_hcd *da8xx_ohci;
struct usb_hcd *hcd;
struct resource *mem;
int error, irq;
@@ -268,30 +286,34 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
if (!hcd)
return -ENOMEM;
- usb11_clk = devm_clk_get(&pdev->dev, "usb11");
- if (IS_ERR(usb11_clk)) {
- if (PTR_ERR(usb11_clk) != -EPROBE_DEFER)
+ da8xx_ohci = to_da8xx_ohci(hcd);
+ da8xx_ohci->hcd = hcd;
+
+ da8xx_ohci->usb11_clk = devm_clk_get(&pdev->dev, "usb11");
+ if (IS_ERR(da8xx_ohci->usb11_clk)) {
+ if (PTR_ERR(da8xx_ohci->usb11_clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to get clock.\n");
- return PTR_ERR(usb11_clk);
+ return PTR_ERR(da8xx_ohci->usb11_clk);
}
- usb11_phy = devm_phy_get(&pdev->dev, "usb-phy");
- if (IS_ERR(usb11_phy)) {
- if (PTR_ERR(usb11_phy) != -EPROBE_DEFER)
+ da8xx_ohci->usb11_phy = devm_phy_get(&pdev->dev, "usb-phy");
+ if (IS_ERR(da8xx_ohci->usb11_phy)) {
+ if (PTR_ERR(da8xx_ohci->usb11_phy) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to get phy.\n");
- return PTR_ERR(usb11_phy);
+ return PTR_ERR(da8xx_ohci->usb11_phy);
}
- vbus_reg = devm_regulator_get(&pdev->dev, "vbus");
- if (IS_ERR(vbus_reg)) {
- if (PTR_ERR(vbus_reg) != -EPROBE_DEFER)
+ da8xx_ohci->vbus_reg = devm_regulator_get(&pdev->dev, "vbus");
+ if (IS_ERR(da8xx_ohci->vbus_reg)) {
+ if (PTR_ERR(da8xx_ohci->vbus_reg) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to get regulator.\n");
- return PTR_ERR(vbus_reg);
+ return PTR_ERR(da8xx_ohci->vbus_reg);
}
- if (vbus_reg) {
- nb.notifier_call = ohci_da8xx_regulator_event;
- error = devm_regulator_register_notifier(vbus_reg, &nb);
+ if (da8xx_ohci->vbus_reg) {
+ da8xx_ohci->nb.notifier_call = ohci_da8xx_regulator_event;
+ error = devm_regulator_register_notifier(da8xx_ohci->vbus_reg,
+ &da8xx_ohci->nb);
if (error) {
dev_err(&pdev->dev,
"Could not register regulator notifier\n");
@@ -354,7 +376,7 @@ static int ohci_da8xx_suspend(struct platform_device *pdev,
if (ret)
return ret;
- ohci_da8xx_disable();
+ ohci_da8xx_disable(hcd);
hcd->state = HC_STATE_SUSPENDED;
return ret;
@@ -370,7 +392,7 @@ static int ohci_da8xx_resume(struct platform_device *dev)
msleep(5);
ohci->next_statechange = jiffies;
- ret = ohci_da8xx_enable();
+ ret = ohci_da8xx_enable(hcd);
if (ret)
return ret;
@@ -382,7 +404,8 @@ static int ohci_da8xx_resume(struct platform_device *dev)
#endif
static const struct ohci_driver_overrides da8xx_overrides __initconst = {
- .reset = ohci_da8xx_reset
+ .reset = ohci_da8xx_reset,
+ .extra_priv_size = sizeof(struct da8xx_ohci_hcd),
};
/*
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 14/17] ARM: davinci: register the usb20_phy clock on the DT file
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
The usb20_phy clock needs to be registered for the driver to be able
to get and enable a clock. Currently the usb phy clocks are registered
form board files, which will not be called during a device tree based
boot.
To be able to probe correctly usb form a device tree boot, register
the usb phy clocks form the DT specific init.
Unfourtunatly, davinci does not have proper clock support on device tree
yet, so by registering the clock form de DT specific file we are
forced to hardcode the parent clock, and cannot select refclkin as
parent for any of the phy clocks of the da850 family.
As none of the current da850 based boards currently in mainline use
refclkin as source. I guess we can live with this limitation until clocks
are correctly represented through CCF/device tree.
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/mach-davinci/da8xx-dt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-davinci/da8xx-dt.c b/arch/arm/mach-davinci/da8xx-dt.c
index c9f7e92..7947267 100644
--- a/arch/arm/mach-davinci/da8xx-dt.c
+++ b/arch/arm/mach-davinci/da8xx-dt.c
@@ -45,6 +45,8 @@
static void __init da850_init_machine(void)
{
+ da8xx_register_usb20_phy_clk(false);
+ da8xx_register_usb11_phy_clk(false);
of_platform_default_populate(NULL, da850_auxdata_lookup, NULL);
}
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 15/17] usb: host: ohci-da8xx: Add devicetree bindings documentation
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
This patch documents the device tree bindings required for
the ohci controller found in TI da8xx family of SoC's
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
.../devicetree/bindings/usb/ohci-da8xx.txt | 39 ++++++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 Documentation/devicetree/bindings/usb/ohci-da8xx.txt
diff --git a/Documentation/devicetree/bindings/usb/ohci-da8xx.txt b/Documentation/devicetree/bindings/usb/ohci-da8xx.txt
new file mode 100644
index 0000000..4251c84
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ohci-da8xx.txt
@@ -0,0 +1,39 @@
+DA8XX USB OHCI controller
+
+Required properties:
+
+ - compatible: Should be "ti,da830-ohci"
+ - reg: Should contain one register range i.e. start and length
+ - interrupts: Description of the interrupt line
+ - phys: Phandle for the PHY device
+ - phy-names: Should be "usb-phy"
+
+Optional properties:
+ - vbus-supply: Regulator that controls vbus power
+
+Example for omap138-lck:
+
+vbus_fixed: fixed-regulator-vbus {
+ compatible = "regulator-fixed";
+ gpio = <&gpio 109 0>;
+ oc-gpio = <&gpio 36 0>;
+ regulator-boot-on;
+ enable-active-high;
+ regulator-name = "vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+};
+
+usb_phy: usb-phy {
+ compatible = "ti,da830-usb-phy";
+ #phy-cells = <1>;
+ status = "disabled";
+};
+usb: usb at 0225000 {
+ compatible = "ti,da830-ohci";
+ reg = <0x225000 0x1000>;
+ interrupts = <59>;
+ phys = <&usb_phy 1>;
+ phy-names = "usb-phy";
+ status = "disabled";
+};
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 16/17] USB: ohci-da8xx: Allow probing from DT
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
This adds the compatible string to the ohci driver
to be able to probe from DT
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
drivers/usb/host/ohci-da8xx.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index bebc3f0..1a8db25 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -273,6 +273,13 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+static const struct of_device_id da8xx_ohci_ids[] = {
+ { .compatible = "ti,da830-ohci" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da8xx_ohci_ids);
+#endif
static int ohci_da8xx_probe(struct platform_device *pdev)
{
@@ -421,6 +428,7 @@ static int ohci_da8xx_resume(struct platform_device *dev)
#endif
.driver = {
.name = "ohci",
+ .of_match_table = da8xx_ohci_ids,
},
};
--
1.9.1
^ permalink raw reply related
* [PATCH/RFT v2 17/17] ARM: dts: da850: add usb device node
From: ahaslam at baylibre.com @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161024164634.4330-1-ahaslam@baylibre.com>
From: Axel Haslam <ahaslam@baylibre.com>
This adds the usb (ohci) device node for the da850 soc.
Also it enables it for the lcdk board
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
---
arch/arm/boot/dts/da850-lcdk.dts | 8 ++++++++
arch/arm/boot/dts/da850.dtsi | 8 ++++++++
2 files changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/da850-lcdk.dts b/arch/arm/boot/dts/da850-lcdk.dts
index 7b8ab21..fa91339 100644
--- a/arch/arm/boot/dts/da850-lcdk.dts
+++ b/arch/arm/boot/dts/da850-lcdk.dts
@@ -86,6 +86,14 @@
};
};
+&usb_phy {
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+};
+
&serial2 {
pinctrl-names = "default";
pinctrl-0 = <&serial2_rxtx_pins>;
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 33fcdce..ec2cec3 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -381,6 +381,14 @@
#phy-cells = <1>;
status = "disabled";
};
+ usb: usb at 0225000 {
+ compatible = "ti,da830-ohci";
+ reg = <0x225000 0x1000>;
+ interrupts = <59>;
+ phys = <&usb_phy 1>;
+ phy-names = "usb-phy";
+ status = "disabled";
+ };
gpio: gpio at 226000 {
compatible = "ti,dm6441-gpio";
gpio-controller;
--
1.9.1
^ permalink raw reply related
* [RFC] da850: DDR2/mDDR memory controller driver
From: Bartosz Golaszewski @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
This is a follow-up for the series[1] adding new bus and memory drivers
to better support the TI LCD controller on the da850-lcdk board.
The general consensus of the discussion that followed was that DT is
not the right tool for this kind of SoC performance tweaks.
In order to avoid committing to stable DT bindings, we only introduce
two common properties (compatible and reg) while the configuration
register values are hard-coded for each board (currently only lcdk).
I'm sending a single patch this time as RFC to get some reviews and
see it the approach is viewed as correct.
[1] https://lkml.org/lkml/2016/10/17/613
Bartosz Golaszewski (1):
ARM: memory: da8xx-ddrctl: new driver
.../memory-controllers/ti-da8xx-ddrctl.txt | 20 +++
drivers/memory/Kconfig | 8 +
drivers/memory/Makefile | 1 +
drivers/memory/da8xx-ddrctl.c | 187 +++++++++++++++++++++
4 files changed, 216 insertions(+)
create mode 100644 Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
create mode 100644 drivers/memory/da8xx-ddrctl.c
--
2.9.3
^ permalink raw reply
* [RFC] ARM: memory: da8xx-ddrctl: new driver
From: Bartosz Golaszewski @ 2016-10-24 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477327596-16060-1-git-send-email-bgolaszewski@baylibre.com>
Create a new driver for the da8xx DDR2/mDDR controller and implement
support for writing to the Peripheral Bus Burst Priority Register.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
.../memory-controllers/ti-da8xx-ddrctl.txt | 20 +++
drivers/memory/Kconfig | 8 +
drivers/memory/Makefile | 1 +
drivers/memory/da8xx-ddrctl.c | 187 +++++++++++++++++++++
4 files changed, 216 insertions(+)
create mode 100644 Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
create mode 100644 drivers/memory/da8xx-ddrctl.c
diff --git a/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
new file mode 100644
index 0000000..f0eda59
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
@@ -0,0 +1,20 @@
+* Device tree bindings for Texas Instruments da8xx DDR2/mDDR memory controller
+
+The DDR2/mDDR memory controller present on Texas Instruments da8xx SoCs memory
+maps a set of registers which allow to tweak the controller's behavior.
+
+Documentation:
+OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf
+
+Required properties:
+
+- compatible: "ti,da850-ddrctl" - for da850 SoC based boards
+- reg: a tuple containing the base address of the memory
+ controller and the size of the memory area to map
+
+Example for da850 shown below.
+
+ddrctl {
+ compatible = "ti,da850-ddrctl";
+ reg = <0xB0000000 0x100>;
+};
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 4b4c0c3..ec80e35 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -134,6 +134,14 @@ config MTK_SMI
mainly help enable/disable iommu and control the power domain and
clocks for each local arbiter.
+config DA8XX_DDRCTL
+ bool "Texas Instruments da8xx DDR2/mDDR driver"
+ depends on ARCH_DAVINCI_DA8XX
+ help
+ This driver is for the DDR2/mDDR Memory Controller present on
+ Texas Instruments da8xx SoCs. It's used to tweak various memory
+ controller configuration options.
+
source "drivers/memory/samsung/Kconfig"
source "drivers/memory/tegra/Kconfig"
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index b20ae38..e88097fb 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o
obj-$(CONFIG_MTK_SMI) += mtk-smi.o
+obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
obj-$(CONFIG_SAMSUNG_MC) += samsung/
obj-$(CONFIG_TEGRA_MC) += tegra/
diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c
new file mode 100644
index 0000000..756a6f3
--- /dev/null
+++ b/drivers/memory/da8xx-ddrctl.c
@@ -0,0 +1,187 @@
+/*
+ * TI da8xx DDR2/mDDR controller driver
+ *
+ * Copyright (C) 2016 BayLibre SAS
+ *
+ * Author:
+ * Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ *
+ * 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/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+struct da8xx_ddrctl_config_knob {
+ const char *name;
+ u32 reg;
+ u32 mask;
+ u32 offset;
+};
+
+static const struct da8xx_ddrctl_config_knob da8xx_ddrctl_knobs[] = {
+ {
+ .name = "da850-pbbpr",
+ .reg = 0x20,
+ .mask = 0xffffff00,
+ .offset = 0,
+ },
+};
+
+struct da8xx_ddrctl_setting {
+ const char *name;
+ u32 val;
+};
+
+struct da8xx_ddrctl_board_settings {
+ const char *board;
+ const struct da8xx_ddrctl_setting *settings;
+};
+
+static const struct da8xx_ddrctl_setting da850_lcdk_ddrctl_settings[] = {
+ {
+ .name = "da850-pbbpr",
+ .val = 0x20,
+ },
+ { }
+};
+
+static const struct da8xx_ddrctl_board_settings da8xx_ddrctl_board_confs[] = {
+ {
+ .board = "ti,da850-lcdk",
+ .settings = da850_lcdk_ddrctl_settings,
+ },
+};
+
+static const struct da8xx_ddrctl_config_knob *
+da8xx_ddrctl_match_knob(const struct da8xx_ddrctl_setting *setting)
+{
+ const struct da8xx_ddrctl_config_knob *knob;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_knobs); i++) {
+ knob = &da8xx_ddrctl_knobs[i];
+
+ if (strcmp(knob->name, setting->name) == 0) {
+ return knob;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct da8xx_ddrctl_setting *
+da8xx_ddrctl_match_board(const char *board)
+{
+ const struct da8xx_ddrctl_board_settings *board_settings;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_board_confs); i++) {
+ board_settings = &da8xx_ddrctl_board_confs[0];
+
+ if (strcmp(board, board_settings->board) == 0)
+ return board_settings->settings;
+ }
+
+ return NULL;
+}
+
+static int da8xx_ddrctl_probe(struct platform_device *pdev)
+{
+ const struct da8xx_ddrctl_config_knob *knob;
+ const struct da8xx_ddrctl_setting *setting;
+ u32 regprop[2], base, memsize, reg;
+ struct device_node *node, *parent;
+ void __iomem *ddrctl;
+ const char *board;
+ struct device *dev;
+ int ret;
+
+ dev = &pdev->dev;
+ node = dev->of_node;
+
+ /* Find the board name. */
+ for (parent = node;
+ !of_node_is_root(parent);
+ parent = of_get_parent(parent));
+
+ ret = of_property_read_string(parent, "compatible", &board);
+ if (ret) {
+ dev_err(dev, "unable to read the soc model\n");
+ return ret;
+ }
+
+ /* Check if we have settings for this board. */
+ setting = da8xx_ddrctl_match_board(board);
+ if (!setting) {
+ dev_err(dev, "no settings for board '%s'\n", board);
+ return -EINVAL;
+ }
+
+ /* Figure out how to map the memory for the controller. */
+ ret = of_property_read_u32_array(node, "reg", regprop, 2);
+ if (ret) {
+ dev_err(dev, "unable to parse 'reg' property\n");
+ return ret;
+ }
+
+ base = regprop[0];
+ memsize = regprop[1];
+
+ ddrctl = ioremap(base, memsize);
+ if (!ddrctl) {
+ dev_err(dev, "unable to map memory controller registers\n");
+ return -EIO;
+ }
+
+ for (; setting->name; setting++) {
+ knob = da8xx_ddrctl_match_knob(setting);
+ if (!knob) {
+ dev_warn(dev,
+ "no such config option: %s\n", setting->name);
+ continue;
+ }
+
+ if (knob->reg > (memsize - sizeof(u32))) {
+ dev_warn(dev,
+ "register offset of '%s' exceeds mapped memory size\n",
+ knob->name);
+ continue;
+ }
+
+ reg = __raw_readl(ddrctl + knob->reg);
+ reg &= knob->mask;
+ reg |= setting->val << knob->offset;
+
+ dev_dbg(dev, "writing 0x%08x to %s\n", reg, setting->name);
+
+ __raw_writel(reg, ddrctl + knob->reg);
+ }
+
+ iounmap(ddrctl);
+
+ return 0;
+}
+
+static const struct of_device_id da8xx_ddrctl_of_match[] = {
+ { .compatible = "ti,da850-ddrctl", },
+ { },
+};
+
+static struct platform_driver da8xx_ddrctl_driver = {
+ .probe = da8xx_ddrctl_probe,
+ .driver = {
+ .name = "da8xx-ddrctl",
+ .of_match_table = da8xx_ddrctl_of_match,
+ },
+};
+module_platform_driver(da8xx_ddrctl_driver);
+
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver");
+MODULE_LICENSE("GPL v2");
--
2.9.3
^ permalink raw reply related
* [PATCH v3 3/8] PM / Domains: Allow domain power states to be read from DT
From: Lina Iyer @ 2016-10-24 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6ed96121-5040-474d-2d71-7927e8567c50@arm.com>
Hi Sudeep,
On Mon, Oct 24 2016 at 07:39 -0600, Sudeep Holla wrote:
>
>
>On 14/10/16 18:47, Lina Iyer wrote:
>>This patch allows domains to define idle states in the DT. SoC's can
>>define domain idle states in DT using the "domain-idle-states" property
>>of the domain provider. Add API to read the idle states from DT that can
>>be set in the genpd object.
>>
>>This patch is based on the original patch by Marc Titinger.
>>
>>Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
>>Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>>Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>>---
>> drivers/base/power/domain.c | 94 +++++++++++++++++++++++++++++++++++++++++++++
>> include/linux/pm_domain.h | 8 ++++
>> 2 files changed, 102 insertions(+)
>>
>>diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>>index 37ab7f1..9af75ba 100644
>>--- a/drivers/base/power/domain.c
>>+++ b/drivers/base/power/domain.c
>>@@ -1916,6 +1916,100 @@ out:
>> return ret ? -EPROBE_DEFER : 0;
>> }
>> EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
>>+
>>+static const struct of_device_id idle_state_match[] = {
>>+ { .compatible = "arm,idle-state", },
>>+ { }
>>+};
>>+
>
>I still think it's better to have another compatible to serve this
>purpose. We don't want to end up creating genpd domains just because
>they are "arm,idle-state" compatible IMO ?
>
>I agree you can prevent it checking for OSC mode support in the
>firmware. But I want to understand if you have any strong reasons for
>avoiding that approach.
>
Why are you still held up with OSI/PC PSCI modes? I repeat again this
series is not about any of that, it is just about PM domains. PM domains
have idle states and the idle-state description is similar in definition
to arm,idle-state and therefore uses the same compatible. There is no
point re-defining something that already exists in the kernel.
I was able to find the original thread, where we discussed this [1].
I suggest, you read about PM domains and its idle states and understand
this series in the context of PM domains.
Thanks,
Lina
[1]. http://www.serverphorums.com/read.php?12,1303996
^ permalink raw reply
* [GIT PULL 4/4] Broadcom defconfig-arm64 changes for 4.9 (part 2)
From: Florian Fainelli @ 2016-10-24 16:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOesGMjJ3_rPUke8B5yW_6Q4NyP1sb-wqY5jfcs1_+UhGQK9_g@mail.gmail.com>
On 10/23/2016 04:50 PM, Olof Johansson wrote:
> On Sun, Oct 23, 2016 at 2:55 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 09/30/2016 12:23 PM, Florian Fainelli wrote:
>>> The following changes since commit 29b4817d4018df78086157ea3a55c1d9424a7cfc:
>>>
>>> Linux 4.8-rc1 (2016-08-07 18:18:00 -0700)
>>>
>>> are available in the git repository at:
>>>
>>> http://github.com/Broadcom/stblinux.git tags/arm-soc/for-4.9/defconfig-arm64
>>>
>>> for you to fetch changes up to 51e3fb1d3f514cd336faf185df73b25fca194773:
>>>
>>> Merge tag 'bcm2835-defconfig-64-next-2016-09-22' into defconfig-arm64/next (2016-09-30 12:02:29 -0700)
>>>
>>> ----------------------------------------------------------------
>>> This pull request contains Broadcom ARM64-based SoCs defconfig changes for 4.9,
>>> please pull the following changes:
>>>
>>> - Eric updates the ARMv8 defconfig to contain everything that is needed to run
>>> a 64-bit kernel on the Raspberry Pi 3
>>>
>>> ----------------------------------------------------------------
>>> Eric Anholt (1):
>>> arm64: Add BCM2835 (Raspberry Pi 3) support to the defconfig
>>>
>>> Florian Fainelli (1):
>>> Merge tag 'bcm2835-defconfig-64-next-2016-09-22' into defconfig-arm64/next
>>>
>>> arch/arm64/configs/defconfig | 16 ++++++++++++++++
>>> 1 file changed, 16 insertions(+)
>>
>> Arnd, Kevin, Olof,
>>
>> Following Olof's response here:
>>
>> https://www.spinics.net/lists/arm-kernel/msg534687.html
>>
>> do you think we could merge these for 4.9-rcX? Let me know if I should
>> send a fresh pull request for that.
>
> Main reason to respin would be if you need to rebase due to other
> changes that have gone in, or if you expect to have other material
> that should be based on a 4.9-rc base.
No dependencies, this should apply cleanly to 4.9-rc. Thanks!
--
Florian
^ permalink raw reply
* Disabling an interrupt in the handler locks the system up
From: Thomas Gleixner @ 2016-10-24 16:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <580E3308.4050507@free.fr>
On Mon, 24 Oct 2016, Mason wrote:
>
> For the record, setting the IRQ_DISABLE_UNLAZY flag for this device
> makes the system lock-up disappear.
The way how lazy irq disabling works is:
1) Interrupt is marked disabled in software, but the hardware is not masked
2) If the interrupt fires befor the interrupt is reenabled, then it's
masked at the hardware level in the low level interrupt flow handler.
I have no idea why that does not work on your hardware. You might
instrument handle_level_irq() to see what effect that has.
Thanks,
tglx
^ permalink raw reply
* [PATCH v2 2/4] dt-bindings: Add TI SCI PM Domains
From: Kevin Hilman @ 2016-10-24 17:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7f4754bb-7ded-6ce3-9558-a45b0d2b3888@ti.com>
Dave Gerlach <d-gerlach@ti.com> writes:
> Hi,
> On 10/21/2016 01:48 PM, Kevin Hilman wrote:
>> Dave Gerlach <d-gerlach@ti.com> writes:
>>
>>> Add a generic power domain implementation, TI SCI PM Domains, that
>>> will hook into the genpd framework and allow the TI SCI protocol to
>>> control device power states.
>>>
>>> Also, provide macros representing each device index as understood
>>> by TI SCI to be used in the device node power-domain references.
>>> These are identifiers for the K2G devices managed by the PMMC.
>>>
>>> Signed-off-by: Nishanth Menon <nm@ti.com>
>>> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
>>> ---
>>> .../devicetree/bindings/soc/ti/sci-pm-domain.txt | 54 +++++++++++++
>>> MAINTAINERS | 2 +
>>> include/dt-bindings/genpd/k2g.h | 90 ++++++++++++++++++++++
>>> 3 files changed, 146 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>> create mode 100644 include/dt-bindings/genpd/k2g.h
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>> new file mode 100644
>>> index 000000000000..32f38a349656
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>> @@ -0,0 +1,54 @@
>>> +Texas Instruments TI-SCI Generic Power Domain
>>> +---------------------------------------------
>>> +
>>> +Some TI SoCs contain a system controller (like the PMMC, etc...) that is
>>> +responsible for controlling the state of the IPs that are present.
>>> +Communication between the host processor running an OS and the system
>>> +controller happens through a protocol known as TI-SCI [1]. This pm domain
>>> +implementation plugs into the generic pm domain framework and makes use of
>>> +the TI SCI protocol power on and off each device when needed.
>>> +
>>> +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
>>> +
>>> +PM Domain Node
>>> +==============
>>> +The PM domain node represents the global PM domain managed by the PMMC,
>>> +which in this case is the single implementation as documented by the generic
>>> +PM domain bindings in Documentation/devicetree/bindings/power/power_domain.txt.
>>> +
>>> +Required Properties:
>>> +--------------------
>>> +- compatible: should be "ti,sci-pm-domain"
>>> +- #power-domain-cells: Must be 0.
>>> +- ti,sci: Phandle to the TI SCI device to use for managing the devices.
>>>
>>> +Example:
>>> +--------------------
>>> +k2g_pds: k2g_pds {
>>
>> should use generic name like "power-contoller", e.g. k2g_pds: power-controller
>
> Ok, that makes more sense.
>
>>
>>> + compatible = "ti,sci-pm-domain";
>>> + #power-domain-cells = <0>;
>>> + ti,sci = <&pmmc>;
>>> +};
>>> +
>>> +PM Domain Consumers
>>> +===================
>>> +Hardware blocks that require SCI control over their state must provide
>>> +a reference to the sci-pm-domain they are part of and a unique device
>>> +specific ID that identifies the device.
>>> +
>>> +Required Properties:
>>> +--------------------
>>> +- power-domains: phandle pointing to the corresponding PM domain node.
>>> +- ti,sci-id: index representing the device id to be passed oevr SCI to
>>> + be used for device control.
>>
>> This ID doesn't look right.
>>
>> Why not use #power-domain-cells = <1> and pass the index in the DT? ...
>>
>>> +See dt-bindings/genpd/k2g.h for the list of valid identifiers for k2g.
>>> +
>>> +Example:
>>> +--------------------
>>> +uart0: serial at 02530c00 {
>>> + compatible = "ns16550a";
>>> + ...
>>> + power-domains = <&k2g_pds>;
>>> + ti,sci-id = <K2G_DEV_UART0>;
>>
>> ... like this:
>>
>> power-domains = <&k2g_pds K2G_DEV_UART0>;
>
> That's how I did it in version one actually. I was able to define my
> own xlate function to parse the phandle and get that index, but Ulf
> pointed me to this series by Jon Hunter [1] that simplified genpd
> providers and dropped the concept of adding your own xlate. This locks
> the onecell approach to using a fixed static array of genpds that get
> indexed into (without passing the index to the provider, just the
> genpd that's looked up), which doesn't fit our usecase, as we don't
> want a 1 to 1 genpd to device mapping based on the comments provided
> in v1. Now we just use the genpd device attach/detach hooks to parse
> the sci-id and then use it in the genpd device start/stop hooks.
Ah, right. I remember now. This approach allows you to use a single
genpd as discussed earlier.
Makes sense now, suggestion retracted.
Kevin
^ permalink raw reply
* [RFC] ARM: memory: da8xx-ddrctl: new driver
From: Mark Rutland @ 2016-10-24 17:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477327596-16060-2-git-send-email-bgolaszewski@baylibre.com>
On Mon, Oct 24, 2016 at 06:46:36PM +0200, Bartosz Golaszewski wrote:
> Create a new driver for the da8xx DDR2/mDDR controller and implement
> support for writing to the Peripheral Bus Burst Priority Register.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> .../memory-controllers/ti-da8xx-ddrctl.txt | 20 +++
> drivers/memory/Kconfig | 8 +
> drivers/memory/Makefile | 1 +
> drivers/memory/da8xx-ddrctl.c | 187 +++++++++++++++++++++
> 4 files changed, 216 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
> create mode 100644 drivers/memory/da8xx-ddrctl.c
>
> diff --git a/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
> new file mode 100644
> index 0000000..f0eda59
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt
> @@ -0,0 +1,20 @@
> +* Device tree bindings for Texas Instruments da8xx DDR2/mDDR memory controller
> +
> +The DDR2/mDDR memory controller present on Texas Instruments da8xx SoCs memory
> +maps a set of registers which allow to tweak the controller's behavior.
This is a description of the *driver*. The device itself doesn't map
some registers, it features them. Please descrive the *device*.
> +
> +Documentation:
> +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf
> +
> +Required properties:
> +
> +- compatible: "ti,da850-ddrctl" - for da850 SoC based boards
Perhaps:
"ti,da850-ddr-controller"
> +static int da8xx_ddrctl_probe(struct platform_device *pdev)
> +{
> + const struct da8xx_ddrctl_config_knob *knob;
> + const struct da8xx_ddrctl_setting *setting;
> + u32 regprop[2], base, memsize, reg;
> + struct device_node *node, *parent;
> + void __iomem *ddrctl;
> + const char *board;
> + struct device *dev;
> + int ret;
> +
> + dev = &pdev->dev;
> + node = dev->of_node;
> +
> + /* Find the board name. */
> + for (parent = node;
> + !of_node_is_root(parent);
> + parent = of_get_parent(parent));
> +
> + ret = of_property_read_string(parent, "compatible", &board);
> + if (ret) {
> + dev_err(dev, "unable to read the soc model\n");
> + return ret;
> + }
I can see that you want to expose sysfs knobs for this, but is it really
necessary to match boards like this? It's very fragile, and commits us
to maintaining a database of board data (i.e. a board file).
I am very much not keen on that.
> +
> + /* Check if we have settings for this board. */
> + setting = da8xx_ddrctl_match_board(board);
> + if (!setting) {
> + dev_err(dev, "no settings for board '%s'\n", board);
> + return -EINVAL;
> + }
What's wrong with of_machine_is_compatible?
> +
> + /* Figure out how to map the memory for the controller. */
> + ret = of_property_read_u32_array(node, "reg", regprop, 2);
> + if (ret) {
> + dev_err(dev, "unable to parse 'reg' property\n");
> + return ret;
> + }
> +
> + base = regprop[0];
> + memsize = regprop[1];
> +
> + ddrctl = ioremap(base, memsize);
NAK. Use the proper accessors for handling reg entries.
Thanks,
Mark.
^ permalink raw reply
* [PATCH] ARM: dts: sun8i: fix the pinmux for UART1
From: Icenowy Zheng @ 2016-10-24 17:08 UTC (permalink / raw)
To: linux-arm-kernel
When the patch is applied, the allwinner,driver and allwinner,pull
properties are removed.
Although they're described to be optional in the devicetree binding,
without them, the pinmux cannot be initialized, and the uart cannot
be used.
Add them back to fix the problem, and makes the bluetooth on iNet D978
Rev2 board work.
Fixes: 82eec384249f (ARM: dts: sun8i: add pinmux for UART1 at PG)
Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
---
This patch is targeted on 4.9.
arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index 48fc24f..300a1bd 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -282,11 +282,15 @@
uart1_pins_a: uart1 at 0 {
allwinner,pins = "PG6", "PG7";
allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
uart1_pins_cts_rts_a: uart1-cts-rts at 0 {
allwinner,pins = "PG8", "PG9";
allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
mmc0_pins_a: mmc0 at 0 {
--
2.10.1
^ permalink raw reply related
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